blob: f301065cf93d67e22749859fd3ff76f2a6f4933b [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 <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 Butler3670c382020-08-06 23:22:35 -070055GeneralResult<std::vector<ConvertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -070066GeneralResult<OperandType> convert(const hal::V1_0::OperandType& operandType) {
Michael Butlera685c3d2020-02-22 22:37:59 -080067 return static_cast<OperandType>(operandType);
68}
69
Michael Butler3670c382020-08-06 23:22:35 -070070GeneralResult<OperationType> convert(const hal::V1_0::OperationType& operationType) {
Michael Butlera685c3d2020-02-22 22:37:59 -080071 return static_cast<OperationType>(operationType);
72}
73
Michael Butler3670c382020-08-06 23:22:35 -070074GeneralResult<Operand::LifeTime> convert(const hal::V1_0::OperandLifeTime& lifetime) {
Michael Butlera685c3d2020-02-22 22:37:59 -080075 return static_cast<Operand::LifeTime>(lifetime);
76}
77
Michael Butler3670c382020-08-06 23:22:35 -070078GeneralResult<DeviceStatus> convert(const hal::V1_0::DeviceStatus& deviceStatus) {
Michael Butlera685c3d2020-02-22 22:37:59 -080079 return static_cast<DeviceStatus>(deviceStatus);
80}
81
Michael Butler3670c382020-08-06 23:22:35 -070082GeneralResult<Capabilities::PerformanceInfo> convert(
83 const hal::V1_0::PerformanceInfo& performanceInfo) {
Michael Butlera685c3d2020-02-22 22:37:59 -080084 return Capabilities::PerformanceInfo{
85 .execTime = performanceInfo.execTime,
86 .powerUsage = performanceInfo.powerUsage,
87 };
88}
89
Michael Butler3670c382020-08-06 23:22:35 -070090GeneralResult<Capabilities> convert(const hal::V1_0::Capabilities& capabilities) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700104GeneralResult<DataLocation> convert(const hal::V1_0::DataLocation& location) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800105 return DataLocation{
106 .poolIndex = location.poolIndex,
107 .offset = location.offset,
108 .length = location.length,
109 };
110}
111
Michael Butler3670c382020-08-06 23:22:35 -0700112GeneralResult<Operand> convert(const hal::V1_0::Operand& operand) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700123GeneralResult<Operation> convert(const hal::V1_0::Operation& operation) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700131GeneralResult<Model::OperandValues> convert(const hidl_vec<uint8_t>& operandValues) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800132 return Model::OperandValues(operandValues.data(), operandValues.size());
133}
134
Michael Butler3670c382020-08-06 23:22:35 -0700135GeneralResult<Memory> convert(const hidl_memory& memory) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800136 return createSharedMemoryFromHidlMemory(memory);
137}
138
Michael Butler3670c382020-08-06 23:22:35 -0700139GeneralResult<Model> convert(const hal::V1_0::Model& model) {
Michael Butlera685c3d2020-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 Butler3670c382020-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 Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700168GeneralResult<Request::Argument> convert(const hal::V1_0::RequestArgument& argument) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700178GeneralResult<Request> convert(const hal::V1_0::Request& request) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700191GeneralResult<ErrorStatus> convert(const hal::V1_0::ErrorStatus& status) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700200 return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
201 << "Invalid ErrorStatus " << underlyingType(status);
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700213nn::GeneralResult<hidl_vec<ConvertOutput<Type>>> convert(const std::vector<Type>& arguments) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700223nn::GeneralResult<OperandType> convert(const nn::OperandType& operandType) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800224 return static_cast<OperandType>(operandType);
225}
226
Michael Butler3670c382020-08-06 23:22:35 -0700227nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800228 return static_cast<OperationType>(operationType);
229}
230
Michael Butler3670c382020-08-06 23:22:35 -0700231nn::GeneralResult<OperandLifeTime> convert(const nn::Operand::LifeTime& lifetime) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800232 if (lifetime == nn::Operand::LifeTime::POINTER) {
Michael Butler3670c382020-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 Butlera685c3d2020-02-22 22:37:59 -0800235 }
236 return static_cast<OperandLifeTime>(lifetime);
237}
238
Michael Butler3670c382020-08-06 23:22:35 -0700239nn::GeneralResult<DeviceStatus> convert(const nn::DeviceStatus& deviceStatus) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800240 return static_cast<DeviceStatus>(deviceStatus);
241}
242
Michael Butler3670c382020-08-06 23:22:35 -0700243nn::GeneralResult<PerformanceInfo> convert(
244 const nn::Capabilities::PerformanceInfo& performanceInfo) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800245 return PerformanceInfo{
246 .execTime = performanceInfo.execTime,
247 .powerUsage = performanceInfo.powerUsage,
248 };
249}
250
Michael Butler3670c382020-08-06 23:22:35 -0700251nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700260nn::GeneralResult<DataLocation> convert(const nn::DataLocation& location) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800261 return DataLocation{
262 .poolIndex = location.poolIndex,
263 .offset = location.offset,
264 .length = location.length,
265 };
266}
267
Michael Butler3670c382020-08-06 23:22:35 -0700268nn::GeneralResult<Operand> convert(const nn::Operand& operand) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700280nn::GeneralResult<Operation> convert(const nn::Operation& operation) {
Michael Butlera685c3d2020-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 Butler3670c382020-08-06 23:22:35 -0700288nn::GeneralResult<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800289 return hidl_vec<uint8_t>(operandValues.data(), operandValues.data() + operandValues.size());
290}
291
Michael Butler3670c382020-08-06 23:22:35 -0700292nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800293 const auto hidlMemory = hidl_memory(memory.name, memory.handle->handle(), memory.size);
294 // Copy memory to force the native_handle_t to be copied.
295 auto copiedMemory = hidlMemory;
296 return copiedMemory;
297}
298
Michael Butler3670c382020-08-06 23:22:35 -0700299nn::GeneralResult<Model> convert(const nn::Model& model) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800300 if (!hal::utils::hasNoPointerData(model)) {
Michael Butler3670c382020-08-06 23:22:35 -0700301 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
302 << "Mdoel cannot be converted because it contains pointer-based memory";
Michael Butlera685c3d2020-02-22 22:37:59 -0800303 }
304
305 auto operands = NN_TRY(convert(model.main.operands));
306
307 // Update number of consumers.
308 const auto numberOfConsumers =
309 hal::utils::countNumberOfConsumers(operands.size(), model.main.operations);
310 CHECK(operands.size() == numberOfConsumers.size());
311 for (size_t i = 0; i < operands.size(); ++i) {
312 operands[i].numberOfConsumers = numberOfConsumers[i];
313 }
314
315 return Model{
316 .operands = std::move(operands),
317 .operations = NN_TRY(convert(model.main.operations)),
318 .inputIndexes = model.main.inputIndexes,
319 .outputIndexes = model.main.outputIndexes,
320 .operandValues = NN_TRY(convert(model.operandValues)),
321 .pools = NN_TRY(convert(model.pools)),
322 };
323}
324
Michael Butler3670c382020-08-06 23:22:35 -0700325nn::GeneralResult<RequestArgument> convert(const nn::Request::Argument& requestArgument) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800326 if (requestArgument.lifetime == nn::Request::Argument::LifeTime::POINTER) {
Michael Butler3670c382020-08-06 23:22:35 -0700327 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
328 << "Request cannot be converted because it contains pointer-based memory";
Michael Butlera685c3d2020-02-22 22:37:59 -0800329 }
330 const bool hasNoValue = requestArgument.lifetime == nn::Request::Argument::LifeTime::NO_VALUE;
331 return RequestArgument{
332 .hasNoValue = hasNoValue,
333 .location = NN_TRY(convert(requestArgument.location)),
334 .dimensions = requestArgument.dimensions,
335 };
336}
337
Michael Butler3670c382020-08-06 23:22:35 -0700338nn::GeneralResult<hidl_memory> convert(const nn::Request::MemoryPool& memoryPool) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800339 return convert(std::get<nn::Memory>(memoryPool));
340}
341
Michael Butler3670c382020-08-06 23:22:35 -0700342nn::GeneralResult<Request> convert(const nn::Request& request) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800343 if (!hal::utils::hasNoPointerData(request)) {
Michael Butler3670c382020-08-06 23:22:35 -0700344 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
345 << "Request cannot be converted because it contains pointer-based memory";
Michael Butlera685c3d2020-02-22 22:37:59 -0800346 }
347
348 return Request{
349 .inputs = NN_TRY(convert(request.inputs)),
350 .outputs = NN_TRY(convert(request.outputs)),
351 .pools = NN_TRY(convert(request.pools)),
352 };
353}
354
Michael Butler3670c382020-08-06 23:22:35 -0700355nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& status) {
Michael Butlera685c3d2020-02-22 22:37:59 -0800356 switch (status) {
357 case nn::ErrorStatus::NONE:
358 case nn::ErrorStatus::DEVICE_UNAVAILABLE:
359 case nn::ErrorStatus::GENERAL_FAILURE:
360 case nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
361 case nn::ErrorStatus::INVALID_ARGUMENT:
362 return static_cast<ErrorStatus>(status);
363 default:
364 return ErrorStatus::GENERAL_FAILURE;
365 }
366}
367
368} // namespace android::hardware::neuralnetworks::V1_0::utils