blob: b47f25a68c76999b9e4d52df08ed224f8c19c5eb [file] [log] [blame]
Michael Butlera685c3d2020-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.0/types.h>
21#include <android/hardware/neuralnetworks/1.1/types.h>
22#include <nnapi/OperandTypes.h>
23#include <nnapi/OperationTypes.h>
24#include <nnapi/Result.h>
25#include <nnapi/SharedMemory.h>
Michael Butler32acc062020-11-22 19:36:30 -080026#include <nnapi/TypeUtils.h>
Michael Butlera685c3d2020-02-22 22:37:59 -080027#include <nnapi/Types.h>
Michael Butler32acc062020-11-22 19:36:30 -080028#include <nnapi/Validation.h>
Michael Butlera685c3d2020-02-22 22:37:59 -080029#include <nnapi/hal/1.0/Conversions.h>
30#include <nnapi/hal/CommonUtils.h>
31
32#include <algorithm>
33#include <functional>
34#include <iterator>
35#include <type_traits>
36#include <utility>
37
Michael Butler32acc062020-11-22 19:36:30 -080038namespace {
39
40constexpr auto kVersion = android::nn::Version::ANDROID_P;
41
42} // namespace
43
Michael Butlera685c3d2020-02-22 22:37:59 -080044namespace android::nn {
45namespace {
46
47using hardware::hidl_vec;
48
49template <typename Input>
Michael Butler32acc062020-11-22 19:36:30 -080050using unvalidatedConvertOutput =
51 std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
Michael Butlera685c3d2020-02-22 22:37:59 -080052
53template <typename Type>
Michael Butler32acc062020-11-22 19:36:30 -080054GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
55 const hidl_vec<Type>& arguments) {
56 std::vector<unvalidatedConvertOutput<Type>> canonical;
Michael Butlera685c3d2020-02-22 22:37:59 -080057 canonical.reserve(arguments.size());
58 for (const auto& argument : arguments) {
Michael Butler32acc062020-11-22 19:36:30 -080059 canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
60 }
61 return canonical;
62}
63
64template <typename Type>
65decltype(nn::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& halObject) {
66 auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
67 const auto maybeVersion = validate(canonical);
68 if (!maybeVersion.has_value()) {
69 return error() << maybeVersion.error();
70 }
71 const auto version = maybeVersion.value();
72 if (version > kVersion) {
73 return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
Michael Butlera685c3d2020-02-22 22:37:59 -080074 }
75 return canonical;
76}
77
78} // anonymous namespace
79
Michael Butler32acc062020-11-22 19:36:30 -080080GeneralResult<OperationType> unvalidatedConvert(const hal::V1_1::OperationType& operationType) {
Michael Butlera685c3d2020-02-22 22:37:59 -080081 return static_cast<OperationType>(operationType);
82}
83
Michael Butler32acc062020-11-22 19:36:30 -080084GeneralResult<Capabilities> unvalidatedConvert(const hal::V1_1::Capabilities& capabilities) {
85 const auto quantized8Performance =
86 NN_TRY(unvalidatedConvert(capabilities.quantized8Performance));
87 const auto float32Performance = NN_TRY(unvalidatedConvert(capabilities.float32Performance));
Michael Butlera685c3d2020-02-22 22:37:59 -080088 const auto relaxedFloat32toFloat16Performance =
Michael Butler32acc062020-11-22 19:36:30 -080089 NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16Performance));
Michael Butlera685c3d2020-02-22 22:37:59 -080090
91 auto table = hal::utils::makeQuantized8PerformanceConsistentWithP(float32Performance,
92 quantized8Performance);
93
94 return Capabilities{
95 .relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16Performance,
96 .relaxedFloat32toFloat16PerformanceTensor = relaxedFloat32toFloat16Performance,
97 .operandPerformance = std::move(table),
98 };
99}
100
Michael Butler32acc062020-11-22 19:36:30 -0800101GeneralResult<Operation> unvalidatedConvert(const hal::V1_1::Operation& operation) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800102 return Operation{
Michael Butler32acc062020-11-22 19:36:30 -0800103 .type = NN_TRY(unvalidatedConvert(operation.type)),
Michael Butlera685c3d2020-02-22 22:37:59 -0800104 .inputs = operation.inputs,
105 .outputs = operation.outputs,
106 };
107}
108
Michael Butler32acc062020-11-22 19:36:30 -0800109GeneralResult<Model> unvalidatedConvert(const hal::V1_1::Model& model) {
110 auto operations = NN_TRY(unvalidatedConvert(model.operations));
Michael Butlera685c3d2020-02-22 22:37:59 -0800111
112 // Verify number of consumers.
113 const auto numberOfConsumers =
114 hal::utils::countNumberOfConsumers(model.operands.size(), operations);
115 CHECK(model.operands.size() == numberOfConsumers.size());
116 for (size_t i = 0; i < model.operands.size(); ++i) {
117 if (model.operands[i].numberOfConsumers != numberOfConsumers[i]) {
Michael Butler3670c382020-08-06 23:22:35 -0700118 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
119 << "Invalid numberOfConsumers for operand " << i << ", expected "
120 << numberOfConsumers[i] << " but found " << model.operands[i].numberOfConsumers;
Michael Butlera685c3d2020-02-22 22:37:59 -0800121 }
122 }
123
124 auto main = Model::Subgraph{
Michael Butler32acc062020-11-22 19:36:30 -0800125 .operands = NN_TRY(unvalidatedConvert(model.operands)),
Michael Butlera685c3d2020-02-22 22:37:59 -0800126 .operations = std::move(operations),
127 .inputIndexes = model.inputIndexes,
128 .outputIndexes = model.outputIndexes,
129 };
130
131 return Model{
132 .main = std::move(main),
Michael Butler32acc062020-11-22 19:36:30 -0800133 .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
134 .pools = NN_TRY(unvalidatedConvert(model.pools)),
Michael Butlera685c3d2020-02-22 22:37:59 -0800135 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
136 };
137}
138
Michael Butler32acc062020-11-22 19:36:30 -0800139GeneralResult<ExecutionPreference> unvalidatedConvert(
Michael Butler3670c382020-08-06 23:22:35 -0700140 const hal::V1_1::ExecutionPreference& executionPreference) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800141 return static_cast<ExecutionPreference>(executionPreference);
142}
143
Michael Butler32acc062020-11-22 19:36:30 -0800144GeneralResult<Capabilities> convert(const hal::V1_1::Capabilities& capabilities) {
145 return validatedConvert(capabilities);
146}
147
148GeneralResult<Model> convert(const hal::V1_1::Model& model) {
149 return validatedConvert(model);
150}
151
152GeneralResult<ExecutionPreference> convert(
153 const hal::V1_1::ExecutionPreference& executionPreference) {
154 return validatedConvert(executionPreference);
155}
156
Michael Butlera685c3d2020-02-22 22:37:59 -0800157} // namespace android::nn
158
159namespace android::hardware::neuralnetworks::V1_1::utils {
160namespace {
161
Michael Butler32acc062020-11-22 19:36:30 -0800162using utils::unvalidatedConvert;
Michael Butlera685c3d2020-02-22 22:37:59 -0800163
Michael Butler32acc062020-11-22 19:36:30 -0800164nn::GeneralResult<V1_0::PerformanceInfo> unvalidatedConvert(
Michael Butlera685c3d2020-02-22 22:37:59 -0800165 const nn::Capabilities::PerformanceInfo& performanceInfo) {
Michael Butler32acc062020-11-22 19:36:30 -0800166 return V1_0::utils::unvalidatedConvert(performanceInfo);
Michael Butlera685c3d2020-02-22 22:37:59 -0800167}
168
Michael Butler32acc062020-11-22 19:36:30 -0800169nn::GeneralResult<V1_0::Operand> unvalidatedConvert(const nn::Operand& operand) {
170 return V1_0::utils::unvalidatedConvert(operand);
Michael Butlera685c3d2020-02-22 22:37:59 -0800171}
172
Michael Butler32acc062020-11-22 19:36:30 -0800173nn::GeneralResult<hidl_vec<uint8_t>> unvalidatedConvert(
174 const nn::Model::OperandValues& operandValues) {
175 return V1_0::utils::unvalidatedConvert(operandValues);
Michael Butlera685c3d2020-02-22 22:37:59 -0800176}
177
Michael Butler32acc062020-11-22 19:36:30 -0800178nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory) {
179 return V1_0::utils::unvalidatedConvert(memory);
Michael Butlera685c3d2020-02-22 22:37:59 -0800180}
181
182template <typename Input>
Michael Butler32acc062020-11-22 19:36:30 -0800183using unvalidatedConvertOutput =
184 std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
Michael Butlera685c3d2020-02-22 22:37:59 -0800185
186template <typename Type>
Michael Butler32acc062020-11-22 19:36:30 -0800187nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
188 const std::vector<Type>& arguments) {
189 hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
Michael Butlera685c3d2020-02-22 22:37:59 -0800190 for (size_t i = 0; i < arguments.size(); ++i) {
Michael Butler32acc062020-11-22 19:36:30 -0800191 halObject[i] = NN_TRY(unvalidatedConvert(arguments[i]));
Michael Butlera685c3d2020-02-22 22:37:59 -0800192 }
193 return halObject;
194}
195
Michael Butler32acc062020-11-22 19:36:30 -0800196template <typename Type>
197decltype(utils::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& canonical) {
198 const auto maybeVersion = nn::validate(canonical);
199 if (!maybeVersion.has_value()) {
200 return nn::error() << maybeVersion.error();
201 }
202 const auto version = maybeVersion.value();
203 if (version > kVersion) {
204 return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
205 }
206 return utils::unvalidatedConvert(canonical);
207}
208
Michael Butlera685c3d2020-02-22 22:37:59 -0800209} // anonymous namespace
210
Michael Butler32acc062020-11-22 19:36:30 -0800211nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800212 return static_cast<OperationType>(operationType);
213}
214
Michael Butler32acc062020-11-22 19:36:30 -0800215nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800216 return Capabilities{
Michael Butler32acc062020-11-22 19:36:30 -0800217 .float32Performance = NN_TRY(unvalidatedConvert(
Michael Butlera685c3d2020-02-22 22:37:59 -0800218 capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))),
Michael Butler32acc062020-11-22 19:36:30 -0800219 .quantized8Performance = NN_TRY(unvalidatedConvert(
Michael Butlera685c3d2020-02-22 22:37:59 -0800220 capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))),
Michael Butler32acc062020-11-22 19:36:30 -0800221 .relaxedFloat32toFloat16Performance = NN_TRY(
222 unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
Michael Butlera685c3d2020-02-22 22:37:59 -0800223 };
224}
225
Michael Butler32acc062020-11-22 19:36:30 -0800226nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800227 return Operation{
Michael Butler32acc062020-11-22 19:36:30 -0800228 .type = NN_TRY(unvalidatedConvert(operation.type)),
Michael Butlera685c3d2020-02-22 22:37:59 -0800229 .inputs = operation.inputs,
230 .outputs = operation.outputs,
231 };
232}
233
Michael Butler32acc062020-11-22 19:36:30 -0800234nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800235 if (!hal::utils::hasNoPointerData(model)) {
Michael Butler3670c382020-08-06 23:22:35 -0700236 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
Michael Butler32acc062020-11-22 19:36:30 -0800237 << "Mdoel cannot be unvalidatedConverted because it contains pointer-based memory";
Michael Butlera685c3d2020-02-22 22:37:59 -0800238 }
239
Michael Butler32acc062020-11-22 19:36:30 -0800240 auto operands = NN_TRY(unvalidatedConvert(model.main.operands));
Michael Butlera685c3d2020-02-22 22:37:59 -0800241
242 // Update number of consumers.
243 const auto numberOfConsumers =
244 hal::utils::countNumberOfConsumers(operands.size(), model.main.operations);
245 CHECK(operands.size() == numberOfConsumers.size());
246 for (size_t i = 0; i < operands.size(); ++i) {
247 operands[i].numberOfConsumers = numberOfConsumers[i];
248 }
249
250 return Model{
251 .operands = std::move(operands),
Michael Butler32acc062020-11-22 19:36:30 -0800252 .operations = NN_TRY(unvalidatedConvert(model.main.operations)),
Michael Butlera685c3d2020-02-22 22:37:59 -0800253 .inputIndexes = model.main.inputIndexes,
254 .outputIndexes = model.main.outputIndexes,
Michael Butler32acc062020-11-22 19:36:30 -0800255 .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
256 .pools = NN_TRY(unvalidatedConvert(model.pools)),
Michael Butlera685c3d2020-02-22 22:37:59 -0800257 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
258 };
259}
260
Michael Butler32acc062020-11-22 19:36:30 -0800261nn::GeneralResult<ExecutionPreference> unvalidatedConvert(
262 const nn::ExecutionPreference& executionPreference) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800263 return static_cast<ExecutionPreference>(executionPreference);
264}
265
Michael Butler32acc062020-11-22 19:36:30 -0800266nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
267 return validatedConvert(capabilities);
268}
269
270nn::GeneralResult<Model> convert(const nn::Model& model) {
271 return validatedConvert(model);
272}
273
274nn::GeneralResult<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference) {
275 return validatedConvert(executionPreference);
276}
277
Michael Butler98ed9ba2020-12-06 21:50:59 -0800278nn::GeneralResult<V1_0::DeviceStatus> convert(const nn::DeviceStatus& deviceStatus) {
279 return V1_0::utils::convert(deviceStatus);
280}
281
282nn::GeneralResult<V1_0::Request> convert(const nn::Request& request) {
283 return V1_0::utils::convert(request);
284}
285
286nn::GeneralResult<V1_0::ErrorStatus> convert(const nn::ErrorStatus& status) {
287 return V1_0::utils::convert(status);
288}
289
Michael Butlera685c3d2020-02-22 22:37:59 -0800290} // namespace android::hardware::neuralnetworks::V1_1::utils