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_PACKAGES_MODULES_NEURALNETWORKS_COMMON_LEGACY_UTILS_H
21 #define ANDROID_PACKAGES_MODULES_NEURALNETWORKS_COMMON_LEGACY_UTILS_H
22
23 #include <android-base/logging.h>
24 #include <nnapi/TypeUtils.h>
25 #include <nnapi/Types.h>
26
27 #include <tuple>
28 #include <utility>
29 #include <vector>
30
31 #include "NeuralNetworks.h"
32 #include "OperationResolver.h"
33 #include "nnapi/TypeUtils.h"
34 #include "nnapi/Types.h"
35
36 namespace android {
37 namespace nn {
38
39 // The number of data types (OperandCode) defined in NeuralNetworksTypes.h.
40 const int kNumberOfDataTypes = 16;
41
42 // The number of operation types (OperationCode) defined in NeuralNetworksTypes.h.
43 const int kNumberOfOperationTypes = 106;
44
45 #ifdef NN_EXPERIMENTAL_FEATURE
46 const int kNumberOfExperimentalOperationTypes = 1;
47 #endif // NN_EXPERIMENTAL_FEATURE
48
49 static_assert(kNumberOfOperationTypes == BuiltinOperationResolver::kNumberOfOperationTypes);
50
51 // The number of execution preferences defined in NeuralNetworks.h.
52 const int kNumberOfPreferences = 3;
53
54 // The number of data types (OperandCode) defined in NeuralNetworksOEM.h.
55 const int kNumberOfDataTypesOEM = 2;
56
57 // The number of operation types (OperationCode) defined in NeuralNetworksOEM.h.
58 const int kNumberOfOperationTypesOEM = 1;
59
60 // The lowest number assigned to any OEM Code in NeuralNetworksOEM.h.
61 const int kOEMCodeBase = 10000;
62
63 #ifdef NN_DEBUGGABLE
64 #define SHOW_IF_DEBUG(msg) msg
65 #else
66 #define SHOW_IF_DEBUG(msg) ""
67 #endif
68
69 #define NN_RETURN_IF_ERROR(expr) \
70 do { \
71 int _errorCode = (expr); \
72 if (_errorCode != ANEURALNETWORKS_NO_ERROR) { \
73 return _errorCode; \
74 } \
75 } while (0)
76
77 enum class HalVersion : int32_t {
78 UNKNOWN,
79 V1_0,
80 V1_1,
81 V1_2,
82 V1_3,
83 AIDL_V1,
84 AIDL_V2,
85 AIDL_UNSTABLE,
86 // TODO(b/207721221): Add AIDL support to TestPartitioning so that LATEST can be set to AIDL
87 // version.
88 LATEST = V1_3,
89 };
90
91 std::ostream& operator<<(std::ostream& os, const HalVersion& halVersion);
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 Dimensions& dimensions);
192 bool tensorHasUnspecifiedDimensions(const ANeuralNetworksOperandType* type);
193
194 // Returns the number of padding bytes needed to align data starting at `index` with `length` number
195 // of bytes such that `index` + returned number of padding bytes is aligned. Refer to
196 // `getAlignmentForLength` for more information on alignment (such as what the current alignments
197 // are for different data lengths).
198 uint32_t alignBytesNeeded(uint32_t index, size_t length);
199
200 // Does a detailed LOG(INFO) of the model
201 void logModelToInfo(const Model& model);
202
validCode(uint32_t codeCount,uint32_t codeCountOEM,uint32_t code)203 inline bool validCode(uint32_t codeCount, uint32_t codeCountOEM, uint32_t code) {
204 return (code < codeCount) || (code >= kOEMCodeBase && (code - kOEMCodeBase) < codeCountOEM);
205 }
206
207 // Validates an operand type.
208 //
209 // extensionOperandTypeInfo must be nullptr iff the type is not an extension type.
210 //
211 // If allowPartial is true, the dimensions may be underspecified.
212 int validateOperandType(const ANeuralNetworksOperandType& type,
213 const Extension::OperandTypeInformation* const extensionOperandTypeInfo,
214 const char* tag, bool allowPartial);
215 int validateOperandList(uint32_t count, const uint32_t* list, uint32_t operandCount,
216 const char* tag);
217
218 // A set of functions to help validate models containing IF or WHILE operations.
219 struct SubgraphValidationHelper {
220 // Checks if a given operand is a SUBGRAPH operand with a valid offset.
221 std::function<bool(const Operand&)> isValidSubgraphReference;
222 // Gets the input count of a subgraph referenced by a given operand.
223 std::function<uint32_t(const Operand&)> getSubgraphInputCount;
224 // Gets the output count of a subgraph referenced by a given operand.
225 std::function<uint32_t(const Operand&)> getSubgraphOutputCount;
226 // Gets the specified input operand of a subgraph referenced by a given operand.
227 std::function<const Operand*(const Operand&, uint32_t)> getSubgraphInputOperand;
228 // Gets the specified output operand of a subgraph referenced by a given operand.
229 std::function<const Operand*(const Operand&, uint32_t)> getSubgraphOutputOperand;
230 // Whether control flow operations with inner or outer input or output
231 // operands of unknown size are allowed.
232 bool allowControlFlowOperationWithOperandOfUnknownSize;
233 };
234
235 // Returns ANEURALNETWORKS_NO_ERROR if the corresponding operation is defined and can handle the
236 // provided operand types in the given HAL version, otherwise returns ANEURALNETWORKS_BAD_DATA.
237 // The last argument is only used for validating IF and WHILE operations.
238 int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount,
239 const uint32_t* inputIndexes, uint32_t outputCount,
240 const uint32_t* outputIndexes, const std::vector<Operand>& operands,
241 HalVersion halVersion, const SubgraphValidationHelper& helper);
242
getSizeFromInts(int lower,int higher)243 inline size_t getSizeFromInts(int lower, int higher) {
244 return (uint32_t)(lower) + ((uint64_t)(uint32_t)(higher) << 32);
245 }
246
247 // Convert ANEURALNETWORKS_* result code to ErrorStatus.
248 // Not guaranteed to be a 1-to-1 mapping.
249 ErrorStatus convertResultCodeToErrorStatus(int resultCode);
250
251 // Convert ErrorStatus to ANEURALNETWORKS_* result code.
252 // Not guaranteed to be a 1-to-1 mapping.
253 int convertErrorStatusToResultCode(ErrorStatus status);
254
255 // Convert execution results to runtime format. Additionally checks that the
256 // returned results abide by the HAL specification, and logs an error if the
257 // result violates the specification.
258 std::tuple<int, std::vector<OutputShape>, Timing> getExecutionResult(
259 ErrorStatus status, std::vector<OutputShape> outputShapes, Timing timing);
260
convertToCanonicalPriority(int32_t priority)261 constexpr Priority convertToCanonicalPriority(int32_t priority) {
262 switch (priority) {
263 case ANEURALNETWORKS_PRIORITY_LOW:
264 return Priority::LOW;
265 case ANEURALNETWORKS_PRIORITY_MEDIUM:
266 return Priority::MEDIUM;
267 case ANEURALNETWORKS_PRIORITY_HIGH:
268 return Priority::HIGH;
269 }
270 LOG(FATAL) << "unrecognized priority: " << priority;
271 return {};
272 }
273
274 // The function syncWait() has the same semantics as the system function
275 // ::sync_wait(), except that the syncWait() return value is semantically
276 // richer. The timeout parameter is in msecs.
277 enum class FenceState {
278 ACTIVE, // fence has not been signaled
279 SIGNALED, // fence has been signaled
280 ERROR, // fence has been placed in the error state
281 UNKNOWN, // either bad argument passed to syncWait(), or internal error
282 };
283 FenceState syncWait(int fd, int timeout);
284
285 #ifdef NN_DEBUGGABLE
286 uint32_t getProp(const char* str, uint32_t defaultValue = 0);
287 #endif // NN_DEBUGGABLE
288
289 struct ApiVersion {
290 Version canonical;
291 int64_t featureLevel;
292 };
293
294 constexpr auto kHalVersionV1_0ToApi = ApiVersion{.canonical = kVersionFeatureLevel1,
295 .featureLevel = ANEURALNETWORKS_FEATURE_LEVEL_1};
296 constexpr auto kHalVersionV1_1ToApi = ApiVersion{.canonical = kVersionFeatureLevel2,
297 .featureLevel = ANEURALNETWORKS_FEATURE_LEVEL_2};
298 constexpr auto kHalVersionV1_2ToApi = ApiVersion{.canonical = kVersionFeatureLevel3,
299 .featureLevel = ANEURALNETWORKS_FEATURE_LEVEL_3};
300 constexpr auto kHalVersionV1_3ToApi = ApiVersion{.canonical = kVersionFeatureLevel4,
301 .featureLevel = ANEURALNETWORKS_FEATURE_LEVEL_4};
302
303 // Utility that measures time period, in nanoseconds, from creation
304 // to destruction and stores result in the supplied memory location
305 // on destruction
306 struct [[nodiscard]] TimeNanoMeasurer {
307 TimePoint start;
308 uint64_t* saveAt;
309
TimeNanoMeasurerTimeNanoMeasurer310 explicit TimeNanoMeasurer(uint64_t* saveAt) : start(Clock::now()), saveAt(saveAt) {}
~TimeNanoMeasurerTimeNanoMeasurer311 ~TimeNanoMeasurer() { *saveAt = currentDuration(start); }
312 DISALLOW_COPY_AND_ASSIGN(TimeNanoMeasurer);
313
currentDurationTimeNanoMeasurer314 static inline uint64_t currentDuration(const TimePoint& start) {
315 auto end = Clock::now();
316 return std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
317 }
318 };
319
320 } // namespace nn
321 } // namespace android
322
323 #endif // ANDROID_PACKAGES_MODULES_NEURALNETWORKS_COMMON_LEGACY_UTILS_H
324