blob: e8a4f55afd5a2cd8a93bd17297db1c445f6b120f [file] [log] [blame]
Michael Butlerb98aa6d2020-02-22 22:37:59 -08001/*
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#include "Conversions.h"
18
19#include <android-base/logging.h>
20#include <android/hardware/neuralnetworks/1.3/types.h>
21#include <nnapi/OperandTypes.h>
22#include <nnapi/OperationTypes.h>
23#include <nnapi/Result.h>
24#include <nnapi/SharedMemory.h>
25#include <nnapi/TypeUtils.h>
26#include <nnapi/Types.h>
Michael Butler6547b2a2020-11-22 19:36:30 -080027#include <nnapi/Validation.h>
Michael Butlerb98aa6d2020-02-22 22:37:59 -080028#include <nnapi/hal/1.0/Conversions.h>
29#include <nnapi/hal/1.2/Conversions.h>
30#include <nnapi/hal/CommonUtils.h>
Michael Butler4b276a72020-08-06 23:22:35 -070031#include <nnapi/hal/HandleError.h>
Michael Butlerb98aa6d2020-02-22 22:37:59 -080032
33#include <algorithm>
34#include <chrono>
35#include <functional>
36#include <iterator>
37#include <limits>
38#include <type_traits>
39#include <utility>
40
Michael Butler388bceb2021-02-03 15:15:43 -080041#include "Utils.h"
42
Michael Butlerb98aa6d2020-02-22 22:37:59 -080043namespace {
44
Michael Butler4895b4d2021-03-18 21:15:09 -070045std::chrono::nanoseconds makeNanosFromUint64(uint64_t nanoseconds) {
46 constexpr auto kMaxCount = std::chrono::nanoseconds::max().count();
47 using CommonType = std::common_type_t<std::chrono::nanoseconds::rep, uint64_t>;
48 const auto count = std::min<CommonType>(kMaxCount, nanoseconds);
49 return std::chrono::nanoseconds{static_cast<std::chrono::nanoseconds::rep>(count)};
50}
51
52uint64_t makeUint64FromNanos(std::chrono::nanoseconds nanoseconds) {
53 if (nanoseconds < std::chrono::nanoseconds::zero()) {
54 return 0;
55 }
56 constexpr auto kMaxCount = std::numeric_limits<uint64_t>::max();
57 using CommonType = std::common_type_t<std::chrono::nanoseconds::rep, uint64_t>;
58 const auto count = std::min<CommonType>(kMaxCount, nanoseconds.count());
59 return static_cast<uint64_t>(count);
60}
61
Michael Butlerb98aa6d2020-02-22 22:37:59 -080062template <typename Type>
63constexpr std::underlying_type_t<Type> underlyingType(Type value) {
64 return static_cast<std::underlying_type_t<Type>>(value);
65}
66
67} // namespace
68
69namespace android::nn {
70namespace {
71
Michael Butlerb98aa6d2020-02-22 22:37:59 -080072using hardware::hidl_vec;
73
74template <typename Input>
Michael Butler388bceb2021-02-03 15:15:43 -080075using UnvalidatedConvertOutput =
Michael Butler6547b2a2020-11-22 19:36:30 -080076 std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
Michael Butlerb98aa6d2020-02-22 22:37:59 -080077
78template <typename Type>
Michael Butler388bceb2021-02-03 15:15:43 -080079GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
Michael Butler6547b2a2020-11-22 19:36:30 -080080 const hidl_vec<Type>& arguments) {
Michael Butler388bceb2021-02-03 15:15:43 -080081 std::vector<UnvalidatedConvertOutput<Type>> canonical;
Michael Butlerb98aa6d2020-02-22 22:37:59 -080082 canonical.reserve(arguments.size());
83 for (const auto& argument : arguments) {
Michael Butler6547b2a2020-11-22 19:36:30 -080084 canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
Michael Butlerb98aa6d2020-02-22 22:37:59 -080085 }
86 return canonical;
87}
88
89template <typename Type>
Michael Butler388bceb2021-02-03 15:15:43 -080090GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& halObject) {
Michael Butler6547b2a2020-11-22 19:36:30 -080091 auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
Michael Butler388bceb2021-02-03 15:15:43 -080092 NN_TRY(hal::V1_3::utils::compliantVersion(canonical));
Michael Butler6547b2a2020-11-22 19:36:30 -080093 return canonical;
94}
95
96template <typename Type>
Michael Butler388bceb2021-02-03 15:15:43 -080097GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> validatedConvert(
Michael Butler6547b2a2020-11-22 19:36:30 -080098 const hidl_vec<Type>& arguments) {
Michael Butler388bceb2021-02-03 15:15:43 -080099 std::vector<UnvalidatedConvertOutput<Type>> canonical;
Michael Butler6547b2a2020-11-22 19:36:30 -0800100 canonical.reserve(arguments.size());
101 for (const auto& argument : arguments) {
102 canonical.push_back(NN_TRY(validatedConvert(argument)));
103 }
104 return canonical;
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800105}
106
107} // anonymous namespace
108
Michael Butler6547b2a2020-11-22 19:36:30 -0800109GeneralResult<OperandType> unvalidatedConvert(const hal::V1_3::OperandType& operandType) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800110 return static_cast<OperandType>(operandType);
111}
112
Michael Butler6547b2a2020-11-22 19:36:30 -0800113GeneralResult<OperationType> unvalidatedConvert(const hal::V1_3::OperationType& operationType) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800114 return static_cast<OperationType>(operationType);
115}
116
Michael Butler6547b2a2020-11-22 19:36:30 -0800117GeneralResult<Priority> unvalidatedConvert(const hal::V1_3::Priority& priority) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800118 return static_cast<Priority>(priority);
119}
120
Michael Butler6547b2a2020-11-22 19:36:30 -0800121GeneralResult<Capabilities> unvalidatedConvert(const hal::V1_3::Capabilities& capabilities) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800122 const bool validOperandTypes = std::all_of(
123 capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
124 [](const hal::V1_3::Capabilities::OperandPerformance& operandPerformance) {
Michael Butler388bceb2021-02-03 15:15:43 -0800125 return validatedConvert(operandPerformance.type).has_value();
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800126 });
127 if (!validOperandTypes) {
Michael Butler4b276a72020-08-06 23:22:35 -0700128 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
Michael Butler6547b2a2020-11-22 19:36:30 -0800129 << "Invalid OperandType when unvalidatedConverting OperandPerformance in "
130 "Capabilities";
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800131 }
132
Michael Butler6547b2a2020-11-22 19:36:30 -0800133 auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
Michael Butler4b276a72020-08-06 23:22:35 -0700134 auto table = NN_TRY(hal::utils::makeGeneralFailure(
135 Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
136 nn::ErrorStatus::GENERAL_FAILURE));
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800137
138 return Capabilities{
Michael Butler6547b2a2020-11-22 19:36:30 -0800139 .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
140 unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
141 .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
142 unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800143 .operandPerformance = std::move(table),
Michael Butler6547b2a2020-11-22 19:36:30 -0800144 .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
145 .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800146 };
147}
148
Michael Butler6547b2a2020-11-22 19:36:30 -0800149GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800150 const hal::V1_3::Capabilities::OperandPerformance& operandPerformance) {
151 return Capabilities::OperandPerformance{
Michael Butler6547b2a2020-11-22 19:36:30 -0800152 .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
153 .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800154 };
155}
156
Michael Butler6547b2a2020-11-22 19:36:30 -0800157GeneralResult<Operation> unvalidatedConvert(const hal::V1_3::Operation& operation) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800158 return Operation{
Michael Butler6547b2a2020-11-22 19:36:30 -0800159 .type = NN_TRY(unvalidatedConvert(operation.type)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800160 .inputs = operation.inputs,
161 .outputs = operation.outputs,
162 };
163}
164
Michael Butler6547b2a2020-11-22 19:36:30 -0800165GeneralResult<Operand::LifeTime> unvalidatedConvert(
166 const hal::V1_3::OperandLifeTime& operandLifeTime) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800167 return static_cast<Operand::LifeTime>(operandLifeTime);
168}
169
Michael Butler6547b2a2020-11-22 19:36:30 -0800170GeneralResult<Operand> unvalidatedConvert(const hal::V1_3::Operand& operand) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800171 return Operand{
Michael Butler6547b2a2020-11-22 19:36:30 -0800172 .type = NN_TRY(unvalidatedConvert(operand.type)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800173 .dimensions = operand.dimensions,
174 .scale = operand.scale,
175 .zeroPoint = operand.zeroPoint,
Michael Butler6547b2a2020-11-22 19:36:30 -0800176 .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
177 .location = NN_TRY(unvalidatedConvert(operand.location)),
178 .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800179 };
180}
181
Michael Butler6547b2a2020-11-22 19:36:30 -0800182GeneralResult<Model> unvalidatedConvert(const hal::V1_3::Model& model) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800183 return Model{
Michael Butler6547b2a2020-11-22 19:36:30 -0800184 .main = NN_TRY(unvalidatedConvert(model.main)),
185 .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
186 .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
187 .pools = NN_TRY(unvalidatedConvert(model.pools)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800188 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
Michael Butler6547b2a2020-11-22 19:36:30 -0800189 .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800190 };
191}
192
Michael Butler6547b2a2020-11-22 19:36:30 -0800193GeneralResult<Model::Subgraph> unvalidatedConvert(const hal::V1_3::Subgraph& subgraph) {
194 auto operations = NN_TRY(unvalidatedConvert(subgraph.operations));
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800195
196 // Verify number of consumers.
197 const auto numberOfConsumers =
Michael Butler68b69262021-02-09 15:36:11 -0800198 NN_TRY(hal::utils::countNumberOfConsumers(subgraph.operands.size(), operations));
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800199 CHECK(subgraph.operands.size() == numberOfConsumers.size());
200 for (size_t i = 0; i < subgraph.operands.size(); ++i) {
201 if (subgraph.operands[i].numberOfConsumers != numberOfConsumers[i]) {
Michael Butler4b276a72020-08-06 23:22:35 -0700202 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
203 << "Invalid numberOfConsumers for operand " << i << ", expected "
204 << numberOfConsumers[i] << " but found "
205 << subgraph.operands[i].numberOfConsumers;
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800206 }
207 }
208
209 return Model::Subgraph{
Michael Butler6547b2a2020-11-22 19:36:30 -0800210 .operands = NN_TRY(unvalidatedConvert(subgraph.operands)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800211 .operations = std::move(operations),
212 .inputIndexes = subgraph.inputIndexes,
213 .outputIndexes = subgraph.outputIndexes,
214 };
215}
216
Michael Butler6547b2a2020-11-22 19:36:30 -0800217GeneralResult<BufferDesc> unvalidatedConvert(const hal::V1_3::BufferDesc& bufferDesc) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800218 return BufferDesc{.dimensions = bufferDesc.dimensions};
219}
220
Michael Butler6547b2a2020-11-22 19:36:30 -0800221GeneralResult<BufferRole> unvalidatedConvert(const hal::V1_3::BufferRole& bufferRole) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800222 return BufferRole{
223 .modelIndex = bufferRole.modelIndex,
224 .ioIndex = bufferRole.ioIndex,
Xusong Wang3633d072021-03-19 13:58:24 -0700225 .probability = bufferRole.frequency,
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800226 };
227}
228
Michael Butler6547b2a2020-11-22 19:36:30 -0800229GeneralResult<Request> unvalidatedConvert(const hal::V1_3::Request& request) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800230 return Request{
Michael Butler6547b2a2020-11-22 19:36:30 -0800231 .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
232 .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
233 .pools = NN_TRY(unvalidatedConvert(request.pools)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800234 };
235}
236
Michael Butler6547b2a2020-11-22 19:36:30 -0800237GeneralResult<Request::MemoryPool> unvalidatedConvert(
238 const hal::V1_3::Request::MemoryPool& memoryPool) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800239 using Discriminator = hal::V1_3::Request::MemoryPool::hidl_discriminator;
240 switch (memoryPool.getDiscriminator()) {
241 case Discriminator::hidlMemory:
Michael Butlerab2f4822021-02-08 00:05:07 -0800242 return hal::utils::createSharedMemoryFromHidlMemory(memoryPool.hidlMemory());
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800243 case Discriminator::token:
244 return static_cast<Request::MemoryDomainToken>(memoryPool.token());
245 }
Michael Butler4b276a72020-08-06 23:22:35 -0700246 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
247 << "Invalid Request::MemoryPool discriminator "
248 << underlyingType(memoryPool.getDiscriminator());
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800249}
250
Michael Butler6547b2a2020-11-22 19:36:30 -0800251GeneralResult<OptionalTimePoint> unvalidatedConvert(
252 const hal::V1_3::OptionalTimePoint& optionalTimePoint) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800253 using Discriminator = hal::V1_3::OptionalTimePoint::hidl_discriminator;
254 switch (optionalTimePoint.getDiscriminator()) {
255 case Discriminator::none:
Michael Butler4024d8f2020-12-04 17:38:20 -0800256 return {};
Michael Butler4895b4d2021-03-18 21:15:09 -0700257 case Discriminator::nanosecondsSinceEpoch: {
258 const auto currentSteadyTime = std::chrono::steady_clock::now();
259 const auto currentBootTime = Clock::now();
260
261 const auto timeSinceEpoch =
262 makeNanosFromUint64(optionalTimePoint.nanosecondsSinceEpoch());
263 const auto steadyTimePoint = std::chrono::steady_clock::time_point{timeSinceEpoch};
264
265 // Both steadyTimePoint and currentSteadyTime are guaranteed to be non-negative, so this
266 // subtraction will never overflow or underflow.
267 const auto timeRemaining = steadyTimePoint - currentSteadyTime;
268
269 // currentBootTime is guaranteed to be non-negative, so this code only protects against
270 // an overflow.
271 nn::TimePoint bootTimePoint;
272 constexpr auto kZeroNano = std::chrono::nanoseconds::zero();
273 constexpr auto kMaxTime = nn::TimePoint::max();
274 if (timeRemaining > kZeroNano && currentBootTime > kMaxTime - timeRemaining) {
275 bootTimePoint = kMaxTime;
276 } else {
277 bootTimePoint = currentBootTime + timeRemaining;
278 }
279
280 constexpr auto kZeroTime = nn::TimePoint{};
281 return std::max(bootTimePoint, kZeroTime);
282 }
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800283 }
Michael Butler4b276a72020-08-06 23:22:35 -0700284 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
285 << "Invalid OptionalTimePoint discriminator "
286 << underlyingType(optionalTimePoint.getDiscriminator());
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800287}
288
Michael Butler4024d8f2020-12-04 17:38:20 -0800289GeneralResult<OptionalDuration> unvalidatedConvert(
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800290 const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800291 using Discriminator = hal::V1_3::OptionalTimeoutDuration::hidl_discriminator;
292 switch (optionalTimeoutDuration.getDiscriminator()) {
293 case Discriminator::none:
Michael Butler4024d8f2020-12-04 17:38:20 -0800294 return {};
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800295 case Discriminator::nanoseconds:
Michael Butler4024d8f2020-12-04 17:38:20 -0800296 return Duration(optionalTimeoutDuration.nanoseconds());
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800297 }
Michael Butler4b276a72020-08-06 23:22:35 -0700298 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
299 << "Invalid OptionalTimeoutDuration discriminator "
300 << underlyingType(optionalTimeoutDuration.getDiscriminator());
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800301}
302
Michael Butler6547b2a2020-11-22 19:36:30 -0800303GeneralResult<ErrorStatus> unvalidatedConvert(const hal::V1_3::ErrorStatus& status) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800304 switch (status) {
305 case hal::V1_3::ErrorStatus::NONE:
306 case hal::V1_3::ErrorStatus::DEVICE_UNAVAILABLE:
307 case hal::V1_3::ErrorStatus::GENERAL_FAILURE:
308 case hal::V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
309 case hal::V1_3::ErrorStatus::INVALID_ARGUMENT:
310 case hal::V1_3::ErrorStatus::MISSED_DEADLINE_TRANSIENT:
311 case hal::V1_3::ErrorStatus::MISSED_DEADLINE_PERSISTENT:
312 case hal::V1_3::ErrorStatus::RESOURCE_EXHAUSTED_TRANSIENT:
313 case hal::V1_3::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
314 return static_cast<ErrorStatus>(status);
315 }
Michael Butler4b276a72020-08-06 23:22:35 -0700316 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
317 << "Invalid ErrorStatus " << underlyingType(status);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800318}
319
Michael Butler6547b2a2020-11-22 19:36:30 -0800320GeneralResult<Priority> convert(const hal::V1_3::Priority& priority) {
321 return validatedConvert(priority);
322}
323
324GeneralResult<Capabilities> convert(const hal::V1_3::Capabilities& capabilities) {
325 return validatedConvert(capabilities);
326}
327
328GeneralResult<Model> convert(const hal::V1_3::Model& model) {
329 return validatedConvert(model);
330}
331
332GeneralResult<BufferDesc> convert(const hal::V1_3::BufferDesc& bufferDesc) {
333 return validatedConvert(bufferDesc);
334}
335
336GeneralResult<Request> convert(const hal::V1_3::Request& request) {
337 return validatedConvert(request);
338}
339
340GeneralResult<OptionalTimePoint> convert(const hal::V1_3::OptionalTimePoint& optionalTimePoint) {
341 return validatedConvert(optionalTimePoint);
342}
343
Michael Butler4024d8f2020-12-04 17:38:20 -0800344GeneralResult<OptionalDuration> convert(
Michael Butler6547b2a2020-11-22 19:36:30 -0800345 const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration) {
346 return validatedConvert(optionalTimeoutDuration);
347}
348
349GeneralResult<ErrorStatus> convert(const hal::V1_3::ErrorStatus& errorStatus) {
350 return validatedConvert(errorStatus);
351}
352
353GeneralResult<SharedHandle> convert(const hardware::hidl_handle& handle) {
354 return validatedConvert(handle);
355}
356
Michael Butler4b276a72020-08-06 23:22:35 -0700357GeneralResult<std::vector<BufferRole>> convert(
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800358 const hardware::hidl_vec<hal::V1_3::BufferRole>& bufferRoles) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800359 return validatedConvert(bufferRoles);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800360}
361
362} // namespace android::nn
363
364namespace android::hardware::neuralnetworks::V1_3::utils {
365namespace {
366
Michael Butler6547b2a2020-11-22 19:36:30 -0800367using utils::unvalidatedConvert;
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800368
Michael Butler6547b2a2020-11-22 19:36:30 -0800369nn::GeneralResult<V1_0::PerformanceInfo> unvalidatedConvert(
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800370 const nn::Capabilities::PerformanceInfo& performanceInfo) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800371 return V1_0::utils::unvalidatedConvert(performanceInfo);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800372}
373
Michael Butler6547b2a2020-11-22 19:36:30 -0800374nn::GeneralResult<V1_0::DataLocation> unvalidatedConvert(const nn::DataLocation& dataLocation) {
375 return V1_0::utils::unvalidatedConvert(dataLocation);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800376}
377
Michael Butler6547b2a2020-11-22 19:36:30 -0800378nn::GeneralResult<hidl_vec<uint8_t>> unvalidatedConvert(
379 const nn::Model::OperandValues& operandValues) {
380 return V1_0::utils::unvalidatedConvert(operandValues);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800381}
382
Michael Butler6547b2a2020-11-22 19:36:30 -0800383nn::GeneralResult<hidl_handle> unvalidatedConvert(const nn::SharedHandle& handle) {
384 return V1_2::utils::unvalidatedConvert(handle);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800385}
386
Michael Butlerfadeb8a2021-02-07 00:11:13 -0800387nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::SharedMemory& memory) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800388 return V1_0::utils::unvalidatedConvert(memory);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800389}
390
Michael Butler6547b2a2020-11-22 19:36:30 -0800391nn::GeneralResult<V1_0::RequestArgument> unvalidatedConvert(const nn::Request::Argument& argument) {
392 return V1_0::utils::unvalidatedConvert(argument);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800393}
394
Michael Butler6547b2a2020-11-22 19:36:30 -0800395nn::GeneralResult<V1_2::Operand::ExtraParams> unvalidatedConvert(
396 const nn::Operand::ExtraParams& extraParams) {
397 return V1_2::utils::unvalidatedConvert(extraParams);
398}
399
400nn::GeneralResult<V1_2::Model::ExtensionNameAndPrefix> unvalidatedConvert(
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800401 const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800402 return V1_2::utils::unvalidatedConvert(extensionNameAndPrefix);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800403}
404
405template <typename Input>
Michael Butler388bceb2021-02-03 15:15:43 -0800406using UnvalidatedConvertOutput =
Michael Butler6547b2a2020-11-22 19:36:30 -0800407 std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800408
409template <typename Type>
Michael Butler388bceb2021-02-03 15:15:43 -0800410nn::GeneralResult<hidl_vec<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
Michael Butler6547b2a2020-11-22 19:36:30 -0800411 const std::vector<Type>& arguments) {
Michael Butler388bceb2021-02-03 15:15:43 -0800412 hidl_vec<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800413 for (size_t i = 0; i < arguments.size(); ++i) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800414 halObject[i] = NN_TRY(unvalidatedConvert(arguments[i]));
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800415 }
416 return halObject;
417}
418
Michael Butlerfadeb8a2021-02-07 00:11:13 -0800419nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::SharedMemory& memory) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800420 Request::MemoryPool ret;
Michael Butler6547b2a2020-11-22 19:36:30 -0800421 ret.hidlMemory(NN_TRY(unvalidatedConvert(memory)));
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800422 return ret;
423}
424
Michael Butler4b276a72020-08-06 23:22:35 -0700425nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::Request::MemoryDomainToken& token) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800426 Request::MemoryPool ret;
427 ret.token(underlyingType(token));
428 return ret;
429}
430
Michael Butler4b276a72020-08-06 23:22:35 -0700431nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::SharedBuffer& /*buffer*/) {
432 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Unable to make memory pool from IBuffer";
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800433}
434
Michael Butler6547b2a2020-11-22 19:36:30 -0800435using utils::unvalidatedConvert;
436
437template <typename Type>
Michael Butler388bceb2021-02-03 15:15:43 -0800438nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
439 NN_TRY(compliantVersion(canonical));
Michael Butler6547b2a2020-11-22 19:36:30 -0800440 return unvalidatedConvert(canonical);
441}
442
443template <typename Type>
Michael Butler388bceb2021-02-03 15:15:43 -0800444nn::GeneralResult<hidl_vec<UnvalidatedConvertOutput<Type>>> validatedConvert(
Michael Butler6547b2a2020-11-22 19:36:30 -0800445 const std::vector<Type>& arguments) {
Michael Butler388bceb2021-02-03 15:15:43 -0800446 hidl_vec<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
Michael Butler6547b2a2020-11-22 19:36:30 -0800447 for (size_t i = 0; i < arguments.size(); ++i) {
448 halObject[i] = NN_TRY(validatedConvert(arguments[i]));
449 }
450 return halObject;
451}
452
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800453} // anonymous namespace
454
Michael Butler6547b2a2020-11-22 19:36:30 -0800455nn::GeneralResult<OperandType> unvalidatedConvert(const nn::OperandType& operandType) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800456 return static_cast<OperandType>(operandType);
457}
458
Michael Butler6547b2a2020-11-22 19:36:30 -0800459nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800460 return static_cast<OperationType>(operationType);
461}
462
Michael Butler6547b2a2020-11-22 19:36:30 -0800463nn::GeneralResult<Priority> unvalidatedConvert(const nn::Priority& priority) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800464 return static_cast<Priority>(priority);
465}
466
Michael Butler6547b2a2020-11-22 19:36:30 -0800467nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800468 std::vector<nn::Capabilities::OperandPerformance> operandPerformance;
469 operandPerformance.reserve(capabilities.operandPerformance.asVector().size());
470 std::copy_if(capabilities.operandPerformance.asVector().begin(),
471 capabilities.operandPerformance.asVector().end(),
472 std::back_inserter(operandPerformance),
473 [](const nn::Capabilities::OperandPerformance& operandPerformance) {
Michael Butler388bceb2021-02-03 15:15:43 -0800474 return compliantVersion(operandPerformance.type).has_value();
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800475 });
476
477 return Capabilities{
Michael Butler6547b2a2020-11-22 19:36:30 -0800478 .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
479 unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
480 .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
481 unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
482 .operandPerformance = NN_TRY(unvalidatedConvert(operandPerformance)),
483 .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
484 .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800485 };
486}
487
Michael Butler6547b2a2020-11-22 19:36:30 -0800488nn::GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800489 const nn::Capabilities::OperandPerformance& operandPerformance) {
490 return Capabilities::OperandPerformance{
Michael Butler6547b2a2020-11-22 19:36:30 -0800491 .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
492 .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800493 };
494}
495
Michael Butler6547b2a2020-11-22 19:36:30 -0800496nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800497 return Operation{
Michael Butler6547b2a2020-11-22 19:36:30 -0800498 .type = NN_TRY(unvalidatedConvert(operation.type)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800499 .inputs = operation.inputs,
500 .outputs = operation.outputs,
501 };
502}
503
Michael Butler6547b2a2020-11-22 19:36:30 -0800504nn::GeneralResult<OperandLifeTime> unvalidatedConvert(
505 const nn::Operand::LifeTime& operandLifeTime) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800506 if (operandLifeTime == nn::Operand::LifeTime::POINTER) {
Michael Butler4b276a72020-08-06 23:22:35 -0700507 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
Michael Butler6547b2a2020-11-22 19:36:30 -0800508 << "Model cannot be unvalidatedConverted because it contains pointer-based memory";
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800509 }
510 return static_cast<OperandLifeTime>(operandLifeTime);
511}
512
Michael Butler6547b2a2020-11-22 19:36:30 -0800513nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800514 return Operand{
Michael Butler6547b2a2020-11-22 19:36:30 -0800515 .type = NN_TRY(unvalidatedConvert(operand.type)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800516 .dimensions = operand.dimensions,
517 .numberOfConsumers = 0,
518 .scale = operand.scale,
519 .zeroPoint = operand.zeroPoint,
Michael Butler6547b2a2020-11-22 19:36:30 -0800520 .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
521 .location = NN_TRY(unvalidatedConvert(operand.location)),
522 .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800523 };
524}
525
Michael Butler6547b2a2020-11-22 19:36:30 -0800526nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800527 if (!hal::utils::hasNoPointerData(model)) {
Michael Butler4b276a72020-08-06 23:22:35 -0700528 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
Michael Butler6547b2a2020-11-22 19:36:30 -0800529 << "Model cannot be unvalidatedConverted because it contains pointer-based memory";
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800530 }
531
532 return Model{
Michael Butler6547b2a2020-11-22 19:36:30 -0800533 .main = NN_TRY(unvalidatedConvert(model.main)),
534 .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
535 .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
536 .pools = NN_TRY(unvalidatedConvert(model.pools)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800537 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
Michael Butler6547b2a2020-11-22 19:36:30 -0800538 .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800539 };
540}
541
Michael Butler6547b2a2020-11-22 19:36:30 -0800542nn::GeneralResult<Subgraph> unvalidatedConvert(const nn::Model::Subgraph& subgraph) {
543 auto operands = NN_TRY(unvalidatedConvert(subgraph.operands));
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800544
545 // Update number of consumers.
546 const auto numberOfConsumers =
Michael Butler68b69262021-02-09 15:36:11 -0800547 NN_TRY(hal::utils::countNumberOfConsumers(operands.size(), subgraph.operations));
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800548 CHECK(operands.size() == numberOfConsumers.size());
549 for (size_t i = 0; i < operands.size(); ++i) {
550 operands[i].numberOfConsumers = numberOfConsumers[i];
551 }
552
553 return Subgraph{
554 .operands = std::move(operands),
Michael Butler6547b2a2020-11-22 19:36:30 -0800555 .operations = NN_TRY(unvalidatedConvert(subgraph.operations)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800556 .inputIndexes = subgraph.inputIndexes,
557 .outputIndexes = subgraph.outputIndexes,
558 };
559}
560
Michael Butler6547b2a2020-11-22 19:36:30 -0800561nn::GeneralResult<BufferDesc> unvalidatedConvert(const nn::BufferDesc& bufferDesc) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800562 return BufferDesc{.dimensions = bufferDesc.dimensions};
563}
564
Michael Butler6547b2a2020-11-22 19:36:30 -0800565nn::GeneralResult<BufferRole> unvalidatedConvert(const nn::BufferRole& bufferRole) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800566 return BufferRole{
567 .modelIndex = bufferRole.modelIndex,
568 .ioIndex = bufferRole.ioIndex,
Xusong Wang3633d072021-03-19 13:58:24 -0700569 .frequency = bufferRole.probability,
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800570 };
571}
572
Michael Butler6547b2a2020-11-22 19:36:30 -0800573nn::GeneralResult<Request> unvalidatedConvert(const nn::Request& request) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800574 if (!hal::utils::hasNoPointerData(request)) {
Michael Butler4b276a72020-08-06 23:22:35 -0700575 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
Michael Butler6547b2a2020-11-22 19:36:30 -0800576 << "Request cannot be unvalidatedConverted because it contains pointer-based memory";
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800577 }
578
579 return Request{
Michael Butler6547b2a2020-11-22 19:36:30 -0800580 .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
581 .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
582 .pools = NN_TRY(unvalidatedConvert(request.pools)),
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800583 };
584}
585
Michael Butler6547b2a2020-11-22 19:36:30 -0800586nn::GeneralResult<Request::MemoryPool> unvalidatedConvert(
587 const nn::Request::MemoryPool& memoryPool) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800588 return std::visit([](const auto& o) { return makeMemoryPool(o); }, memoryPool);
589}
590
Michael Butler6547b2a2020-11-22 19:36:30 -0800591nn::GeneralResult<OptionalTimePoint> unvalidatedConvert(
592 const nn::OptionalTimePoint& optionalTimePoint) {
Michael Butler4895b4d2021-03-18 21:15:09 -0700593 const auto currentSteadyTime = std::chrono::steady_clock::now();
594 const auto currentBootTime = nn::Clock::now();
595
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800596 OptionalTimePoint ret;
597 if (optionalTimePoint.has_value()) {
Michael Butler4895b4d2021-03-18 21:15:09 -0700598 const auto bootTimePoint = optionalTimePoint.value();
599
600 if (bootTimePoint < nn::TimePoint{}) {
601 return NN_ERROR() << "Trying to cast invalid time point";
602 }
603
604 // Both bootTimePoint and currentBootTime are guaranteed to be non-negative, so this
605 // subtraction will never overflow or underflow.
606 const auto timeRemaining = bootTimePoint - currentBootTime;
607
608 // currentSteadyTime is guaranteed to be non-negative, so this code only protects against an
609 // overflow.
610 std::chrono::steady_clock::time_point steadyTimePoint;
611 constexpr auto kZeroNano = std::chrono::nanoseconds::zero();
612 constexpr auto kMaxTime = std::chrono::steady_clock::time_point::max();
613 if (timeRemaining > kZeroNano && currentSteadyTime > kMaxTime - timeRemaining) {
614 steadyTimePoint = kMaxTime;
615 } else {
616 steadyTimePoint = currentSteadyTime + timeRemaining;
617 }
618
619 const uint64_t count = makeUint64FromNanos(steadyTimePoint.time_since_epoch());
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800620 ret.nanosecondsSinceEpoch(count);
621 }
622 return ret;
623}
624
Michael Butler6547b2a2020-11-22 19:36:30 -0800625nn::GeneralResult<OptionalTimeoutDuration> unvalidatedConvert(
Michael Butler4024d8f2020-12-04 17:38:20 -0800626 const nn::OptionalDuration& optionalTimeoutDuration) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800627 OptionalTimeoutDuration ret;
628 if (optionalTimeoutDuration.has_value()) {
629 const auto count = optionalTimeoutDuration.value().count();
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800630 ret.nanoseconds(count);
631 }
632 return ret;
633}
634
Michael Butler6547b2a2020-11-22 19:36:30 -0800635nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800636 switch (errorStatus) {
637 case nn::ErrorStatus::NONE:
638 case nn::ErrorStatus::DEVICE_UNAVAILABLE:
639 case nn::ErrorStatus::GENERAL_FAILURE:
640 case nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
641 case nn::ErrorStatus::INVALID_ARGUMENT:
642 case nn::ErrorStatus::MISSED_DEADLINE_TRANSIENT:
643 case nn::ErrorStatus::MISSED_DEADLINE_PERSISTENT:
644 case nn::ErrorStatus::RESOURCE_EXHAUSTED_TRANSIENT:
645 case nn::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
646 return static_cast<ErrorStatus>(errorStatus);
647 default:
648 return ErrorStatus::GENERAL_FAILURE;
649 }
650}
651
Michael Butler6547b2a2020-11-22 19:36:30 -0800652nn::GeneralResult<Priority> convert(const nn::Priority& priority) {
653 return validatedConvert(priority);
654}
655
656nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
657 return validatedConvert(capabilities);
658}
659
660nn::GeneralResult<Model> convert(const nn::Model& model) {
661 return validatedConvert(model);
662}
663
664nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc) {
665 return validatedConvert(bufferDesc);
666}
667
668nn::GeneralResult<Request> convert(const nn::Request& request) {
669 return validatedConvert(request);
670}
671
672nn::GeneralResult<OptionalTimePoint> convert(const nn::OptionalTimePoint& optionalTimePoint) {
673 return validatedConvert(optionalTimePoint);
674}
675
676nn::GeneralResult<OptionalTimeoutDuration> convert(
Michael Butler4024d8f2020-12-04 17:38:20 -0800677 const nn::OptionalDuration& optionalTimeoutDuration) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800678 return validatedConvert(optionalTimeoutDuration);
679}
680
681nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus) {
682 return validatedConvert(errorStatus);
683}
684
685nn::GeneralResult<hidl_handle> convert(const nn::SharedHandle& handle) {
686 return validatedConvert(handle);
687}
688
Michael Butlerfadeb8a2021-02-07 00:11:13 -0800689nn::GeneralResult<hidl_memory> convert(const nn::SharedMemory& memory) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800690 return validatedConvert(memory);
691}
692
Michael Butler4b276a72020-08-06 23:22:35 -0700693nn::GeneralResult<hidl_vec<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800694 return validatedConvert(bufferRoles);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800695}
696
Michael Butler7fd03c22020-12-06 21:50:59 -0800697nn::GeneralResult<V1_0::DeviceStatus> convert(const nn::DeviceStatus& deviceStatus) {
698 return V1_2::utils::convert(deviceStatus);
699}
700
701nn::GeneralResult<V1_1::ExecutionPreference> convert(
702 const nn::ExecutionPreference& executionPreference) {
703 return V1_2::utils::convert(executionPreference);
704}
705
706nn::GeneralResult<hidl_vec<V1_2::Extension>> convert(const std::vector<nn::Extension>& extensions) {
707 return V1_2::utils::convert(extensions);
708}
709
710nn::GeneralResult<hidl_vec<hidl_handle>> convert(const std::vector<nn::SharedHandle>& handles) {
711 return V1_2::utils::convert(handles);
712}
713
714nn::GeneralResult<hidl_vec<V1_2::OutputShape>> convert(
715 const std::vector<nn::OutputShape>& outputShapes) {
716 return V1_2::utils::convert(outputShapes);
717}
718
719nn::GeneralResult<V1_2::DeviceType> convert(const nn::DeviceType& deviceType) {
720 return V1_2::utils::convert(deviceType);
721}
722
723nn::GeneralResult<V1_2::MeasureTiming> convert(const nn::MeasureTiming& measureTiming) {
724 return V1_2::utils::convert(measureTiming);
725}
726
727nn::GeneralResult<V1_2::Timing> convert(const nn::Timing& timing) {
728 return V1_2::utils::convert(timing);
729}
730
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800731} // namespace android::hardware::neuralnetworks::V1_3::utils