blob: 6cf907380e60b2a34e5a4e1843b46c773d50b8c7 [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.0/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/Types.h>
26#include <nnapi/hal/CommonUtils.h>
27
28#include <algorithm>
29#include <functional>
30#include <iterator>
31#include <memory>
32#include <type_traits>
33#include <utility>
34#include <variant>
35
36namespace {
37
38template <typename Type>
39constexpr std::underlying_type_t<Type> underlyingType(Type value) {
40 return static_cast<std::underlying_type_t<Type>>(value);
41}
42
43} // namespace
44
45namespace android::nn {
46namespace {
47
48using hardware::hidl_memory;
49using hardware::hidl_vec;
50
51template <typename Input>
52using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
53
54template <typename Type>
Michael Butler4b276a72020-08-06 23:22:35 -070055GeneralResult<std::vector<ConvertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080056 std::vector<ConvertOutput<Type>> canonical;
57 canonical.reserve(arguments.size());
58 for (const auto& argument : arguments) {
59 canonical.push_back(NN_TRY(nn::convert(argument)));
60 }
61 return canonical;
62}
63
64} // anonymous namespace
65
Michael Butler4b276a72020-08-06 23:22:35 -070066GeneralResult<OperandType> convert(const hal::V1_0::OperandType& operandType) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080067 return static_cast<OperandType>(operandType);
68}
69
Michael Butler4b276a72020-08-06 23:22:35 -070070GeneralResult<OperationType> convert(const hal::V1_0::OperationType& operationType) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080071 return static_cast<OperationType>(operationType);
72}
73
Michael Butler4b276a72020-08-06 23:22:35 -070074GeneralResult<Operand::LifeTime> convert(const hal::V1_0::OperandLifeTime& lifetime) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080075 return static_cast<Operand::LifeTime>(lifetime);
76}
77
Michael Butler4b276a72020-08-06 23:22:35 -070078GeneralResult<DeviceStatus> convert(const hal::V1_0::DeviceStatus& deviceStatus) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080079 return static_cast<DeviceStatus>(deviceStatus);
80}
81
Michael Butler4b276a72020-08-06 23:22:35 -070082GeneralResult<Capabilities::PerformanceInfo> convert(
83 const hal::V1_0::PerformanceInfo& performanceInfo) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080084 return Capabilities::PerformanceInfo{
85 .execTime = performanceInfo.execTime,
86 .powerUsage = performanceInfo.powerUsage,
87 };
88}
89
Michael Butler4b276a72020-08-06 23:22:35 -070090GeneralResult<Capabilities> convert(const hal::V1_0::Capabilities& capabilities) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080091 const auto quantized8Performance = NN_TRY(convert(capabilities.quantized8Performance));
92 const auto float32Performance = NN_TRY(convert(capabilities.float32Performance));
93
94 auto table = hal::utils::makeQuantized8PerformanceConsistentWithP(float32Performance,
95 quantized8Performance);
96
97 return Capabilities{
98 .relaxedFloat32toFloat16PerformanceScalar = float32Performance,
99 .relaxedFloat32toFloat16PerformanceTensor = float32Performance,
100 .operandPerformance = std::move(table),
101 };
102}
103
Michael Butler4b276a72020-08-06 23:22:35 -0700104GeneralResult<DataLocation> convert(const hal::V1_0::DataLocation& location) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800105 return DataLocation{
106 .poolIndex = location.poolIndex,
107 .offset = location.offset,
108 .length = location.length,
109 };
110}
111
Michael Butler4b276a72020-08-06 23:22:35 -0700112GeneralResult<Operand> convert(const hal::V1_0::Operand& operand) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800113 return Operand{
114 .type = NN_TRY(convert(operand.type)),
115 .dimensions = operand.dimensions,
116 .scale = operand.scale,
117 .zeroPoint = operand.zeroPoint,
118 .lifetime = NN_TRY(convert(operand.lifetime)),
119 .location = NN_TRY(convert(operand.location)),
120 };
121}
122
Michael Butler4b276a72020-08-06 23:22:35 -0700123GeneralResult<Operation> convert(const hal::V1_0::Operation& operation) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800124 return Operation{
125 .type = NN_TRY(convert(operation.type)),
126 .inputs = operation.inputs,
127 .outputs = operation.outputs,
128 };
129}
130
Michael Butler4b276a72020-08-06 23:22:35 -0700131GeneralResult<Model::OperandValues> convert(const hidl_vec<uint8_t>& operandValues) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800132 return Model::OperandValues(operandValues.data(), operandValues.size());
133}
134
Michael Butler4b276a72020-08-06 23:22:35 -0700135GeneralResult<Memory> convert(const hidl_memory& memory) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800136 return createSharedMemoryFromHidlMemory(memory);
137}
138
Michael Butler4b276a72020-08-06 23:22:35 -0700139GeneralResult<Model> convert(const hal::V1_0::Model& model) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800140 auto operations = NN_TRY(convert(model.operations));
141
142 // Verify number of consumers.
143 const auto numberOfConsumers =
144 hal::utils::countNumberOfConsumers(model.operands.size(), operations);
145 CHECK(model.operands.size() == numberOfConsumers.size());
146 for (size_t i = 0; i < model.operands.size(); ++i) {
147 if (model.operands[i].numberOfConsumers != numberOfConsumers[i]) {
Michael Butler4b276a72020-08-06 23:22:35 -0700148 return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
149 << "Invalid numberOfConsumers for operand " << i << ", expected "
150 << numberOfConsumers[i] << " but found " << model.operands[i].numberOfConsumers;
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800151 }
152 }
153
154 auto main = Model::Subgraph{
155 .operands = NN_TRY(convert(model.operands)),
156 .operations = std::move(operations),
157 .inputIndexes = model.inputIndexes,
158 .outputIndexes = model.outputIndexes,
159 };
160
161 return Model{
162 .main = std::move(main),
163 .operandValues = NN_TRY(convert(model.operandValues)),
164 .pools = NN_TRY(convert(model.pools)),
165 };
166}
167
Michael Butler4b276a72020-08-06 23:22:35 -0700168GeneralResult<Request::Argument> convert(const hal::V1_0::RequestArgument& argument) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800169 const auto lifetime = argument.hasNoValue ? Request::Argument::LifeTime::NO_VALUE
170 : Request::Argument::LifeTime::POOL;
171 return Request::Argument{
172 .lifetime = lifetime,
173 .location = NN_TRY(convert(argument.location)),
174 .dimensions = argument.dimensions,
175 };
176}
177
Michael Butler4b276a72020-08-06 23:22:35 -0700178GeneralResult<Request> convert(const hal::V1_0::Request& request) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800179 auto memories = NN_TRY(convert(request.pools));
180 std::vector<Request::MemoryPool> pools;
181 pools.reserve(memories.size());
182 std::move(memories.begin(), memories.end(), std::back_inserter(pools));
183
184 return Request{
185 .inputs = NN_TRY(convert(request.inputs)),
186 .outputs = NN_TRY(convert(request.outputs)),
187 .pools = std::move(pools),
188 };
189}
190
Michael Butler4b276a72020-08-06 23:22:35 -0700191GeneralResult<ErrorStatus> convert(const hal::V1_0::ErrorStatus& status) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800192 switch (status) {
193 case hal::V1_0::ErrorStatus::NONE:
194 case hal::V1_0::ErrorStatus::DEVICE_UNAVAILABLE:
195 case hal::V1_0::ErrorStatus::GENERAL_FAILURE:
196 case hal::V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
197 case hal::V1_0::ErrorStatus::INVALID_ARGUMENT:
198 return static_cast<ErrorStatus>(status);
199 }
Michael Butler4b276a72020-08-06 23:22:35 -0700200 return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
201 << "Invalid ErrorStatus " << underlyingType(status);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800202}
203
204} // namespace android::nn
205
206namespace android::hardware::neuralnetworks::V1_0::utils {
207namespace {
208
209template <typename Input>
210using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
211
212template <typename Type>
Michael Butler4b276a72020-08-06 23:22:35 -0700213nn::GeneralResult<hidl_vec<ConvertOutput<Type>>> convert(const std::vector<Type>& arguments) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800214 hidl_vec<ConvertOutput<Type>> halObject(arguments.size());
215 for (size_t i = 0; i < arguments.size(); ++i) {
216 halObject[i] = NN_TRY(utils::convert(arguments[i]));
217 }
218 return halObject;
219}
220
221} // anonymous namespace
222
Michael Butler4b276a72020-08-06 23:22:35 -0700223nn::GeneralResult<OperandType> convert(const nn::OperandType& operandType) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800224 return static_cast<OperandType>(operandType);
225}
226
Michael Butler4b276a72020-08-06 23:22:35 -0700227nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800228 return static_cast<OperationType>(operationType);
229}
230
Michael Butler4b276a72020-08-06 23:22:35 -0700231nn::GeneralResult<OperandLifeTime> convert(const nn::Operand::LifeTime& lifetime) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800232 if (lifetime == nn::Operand::LifeTime::POINTER) {
Michael Butler4b276a72020-08-06 23:22:35 -0700233 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
234 << "Model cannot be converted because it contains pointer-based memory";
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800235 }
236 return static_cast<OperandLifeTime>(lifetime);
237}
238
Michael Butler4b276a72020-08-06 23:22:35 -0700239nn::GeneralResult<DeviceStatus> convert(const nn::DeviceStatus& deviceStatus) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800240 return static_cast<DeviceStatus>(deviceStatus);
241}
242
Michael Butler4b276a72020-08-06 23:22:35 -0700243nn::GeneralResult<PerformanceInfo> convert(
244 const nn::Capabilities::PerformanceInfo& performanceInfo) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800245 return PerformanceInfo{
246 .execTime = performanceInfo.execTime,
247 .powerUsage = performanceInfo.powerUsage,
248 };
249}
250
Michael Butler4b276a72020-08-06 23:22:35 -0700251nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800252 return Capabilities{
253 .float32Performance = NN_TRY(convert(
254 capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))),
255 .quantized8Performance = NN_TRY(convert(
256 capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))),
257 };
258}
259
Michael Butler4b276a72020-08-06 23:22:35 -0700260nn::GeneralResult<DataLocation> convert(const nn::DataLocation& location) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800261 return DataLocation{
262 .poolIndex = location.poolIndex,
263 .offset = location.offset,
264 .length = location.length,
265 };
266}
267
Michael Butler4b276a72020-08-06 23:22:35 -0700268nn::GeneralResult<Operand> convert(const nn::Operand& operand) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800269 return Operand{
270 .type = NN_TRY(convert(operand.type)),
271 .dimensions = operand.dimensions,
272 .numberOfConsumers = 0,
273 .scale = operand.scale,
274 .zeroPoint = operand.zeroPoint,
275 .lifetime = NN_TRY(convert(operand.lifetime)),
276 .location = NN_TRY(convert(operand.location)),
277 };
278}
279
Michael Butler4b276a72020-08-06 23:22:35 -0700280nn::GeneralResult<Operation> convert(const nn::Operation& operation) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800281 return Operation{
282 .type = NN_TRY(convert(operation.type)),
283 .inputs = operation.inputs,
284 .outputs = operation.outputs,
285 };
286}
287
Michael Butler4b276a72020-08-06 23:22:35 -0700288nn::GeneralResult<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800289 return hidl_vec<uint8_t>(operandValues.data(), operandValues.data() + operandValues.size());
290}
291
Michael Butler4b276a72020-08-06 23:22:35 -0700292nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory) {
Slava Shklyaev49817a02020-10-27 18:44:01 +0000293 return hidl_memory(memory.name, NN_TRY(hal::utils::hidlHandleFromSharedHandle(memory.handle)),
294 memory.size);
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800295}
296
Michael Butler4b276a72020-08-06 23:22:35 -0700297nn::GeneralResult<Model> convert(const nn::Model& model) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800298 if (!hal::utils::hasNoPointerData(model)) {
Michael Butler4b276a72020-08-06 23:22:35 -0700299 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
300 << "Mdoel cannot be converted because it contains pointer-based memory";
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800301 }
302
303 auto operands = NN_TRY(convert(model.main.operands));
304
305 // Update number of consumers.
306 const auto numberOfConsumers =
307 hal::utils::countNumberOfConsumers(operands.size(), model.main.operations);
308 CHECK(operands.size() == numberOfConsumers.size());
309 for (size_t i = 0; i < operands.size(); ++i) {
310 operands[i].numberOfConsumers = numberOfConsumers[i];
311 }
312
313 return Model{
314 .operands = std::move(operands),
315 .operations = NN_TRY(convert(model.main.operations)),
316 .inputIndexes = model.main.inputIndexes,
317 .outputIndexes = model.main.outputIndexes,
318 .operandValues = NN_TRY(convert(model.operandValues)),
319 .pools = NN_TRY(convert(model.pools)),
320 };
321}
322
Michael Butler4b276a72020-08-06 23:22:35 -0700323nn::GeneralResult<RequestArgument> convert(const nn::Request::Argument& requestArgument) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800324 if (requestArgument.lifetime == nn::Request::Argument::LifeTime::POINTER) {
Michael Butler4b276a72020-08-06 23:22:35 -0700325 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
326 << "Request cannot be converted because it contains pointer-based memory";
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800327 }
328 const bool hasNoValue = requestArgument.lifetime == nn::Request::Argument::LifeTime::NO_VALUE;
329 return RequestArgument{
330 .hasNoValue = hasNoValue,
331 .location = NN_TRY(convert(requestArgument.location)),
332 .dimensions = requestArgument.dimensions,
333 };
334}
335
Michael Butler4b276a72020-08-06 23:22:35 -0700336nn::GeneralResult<hidl_memory> convert(const nn::Request::MemoryPool& memoryPool) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800337 return convert(std::get<nn::Memory>(memoryPool));
338}
339
Michael Butler4b276a72020-08-06 23:22:35 -0700340nn::GeneralResult<Request> convert(const nn::Request& request) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800341 if (!hal::utils::hasNoPointerData(request)) {
Michael Butler4b276a72020-08-06 23:22:35 -0700342 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
343 << "Request cannot be converted because it contains pointer-based memory";
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800344 }
345
346 return Request{
347 .inputs = NN_TRY(convert(request.inputs)),
348 .outputs = NN_TRY(convert(request.outputs)),
349 .pools = NN_TRY(convert(request.pools)),
350 };
351}
352
Michael Butler4b276a72020-08-06 23:22:35 -0700353nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& status) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800354 switch (status) {
355 case nn::ErrorStatus::NONE:
356 case nn::ErrorStatus::DEVICE_UNAVAILABLE:
357 case nn::ErrorStatus::GENERAL_FAILURE:
358 case nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
359 case nn::ErrorStatus::INVALID_ARGUMENT:
360 return static_cast<ErrorStatus>(status);
361 default:
362 return ErrorStatus::GENERAL_FAILURE;
363 }
364}
365
366} // namespace android::hardware::neuralnetworks::V1_0::utils