From b5fdf38f0c6596958fab2b84882f2792a31e585a Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Tue, 11 Jun 2019 16:35:25 +0100 Subject: IVGCVSW-3181 Add HAL 1.2 support to android-nn-driver * Updated Android.mk to build HAL 1.2 driver * Added 1.2 HalPolicy and ArmnnDriver * Added 1.2 ArmnnPreparedModel * Updated converters and utilities to accept new HAL 1.2 operands and operand types. Signed-off-by: Sadik Armagan Signed-off-by: Mike Kelly Change-Id: I62856deab24e106f72cccce09468db4971756fa6 --- 1.2/ArmnnDriverImpl.cpp | 206 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 1.2/ArmnnDriverImpl.cpp (limited to '1.2/ArmnnDriverImpl.cpp') diff --git a/1.2/ArmnnDriverImpl.cpp b/1.2/ArmnnDriverImpl.cpp new file mode 100644 index 00000000..97cfa5de --- /dev/null +++ b/1.2/ArmnnDriverImpl.cpp @@ -0,0 +1,206 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "ArmnnDriverImpl.hpp" +#include "../ArmnnPreparedModel_1_2.hpp" +#include "../ModelToINetworkConverter.hpp" +#include "../SystemPropertiesUtils.hpp" + +#include + +namespace +{ + +const char *g_RelaxedFloat32toFloat16PerformanceExecTime = "ArmNN.relaxedFloat32toFloat16Performance.execTime"; +void NotifyCallbackAndCheck(const sp& callback, + ErrorStatus errorStatus, + const sp& preparedModelPtr) +{ + Return returned = callback->notify(errorStatus, preparedModelPtr); + // This check is required, if the callback fails and it isn't checked it will bring down the service + if (!returned.isOk()) + { + ALOGE("ArmnnDriverImpl::prepareModel: hidl callback failed to return properly: %s ", + returned.description().c_str()); + } +} + +Return FailPrepareModel(ErrorStatus error, + const std::string& message, + const sp& callback) +{ + ALOGW("ArmnnDriverImpl::prepareModel: %s", message.c_str()); + NotifyCallbackAndCheck(callback, error, nullptr); + return error; +} + +} // anonymous namespace + +namespace armnn_driver +{ +namespace hal_1_2 +{ + +Return ArmnnDriverImpl::prepareArmnnModel_1_2(const armnn::IRuntimePtr& runtime, + const armnn::IGpuAccTunedParametersPtr& clTunedParameters, + const DriverOptions& options, + const V1_2::Model& model, + const sp& cb, + bool float32ToFloat16) +{ + ALOGV("ArmnnDriverImpl::prepareModel()"); + + if (cb.get() == nullptr) + { + ALOGW("ArmnnDriverImpl::prepareModel: Invalid callback passed to prepareModel"); + return ErrorStatus::INVALID_ARGUMENT; + } + + if (!runtime) + { + return FailPrepareModel(ErrorStatus::DEVICE_UNAVAILABLE, "Device unavailable", cb); + } + + if (!android::nn::validateModel(model)) + { + return FailPrepareModel(ErrorStatus::INVALID_ARGUMENT, "Invalid model passed as input", cb); + } + + // Deliberately ignore any unsupported operations requested by the options - + // at this point we're being asked to prepare a model that we've already declared support for + // and the operation indices may be different to those in getSupportedOperations anyway. + std::set unsupportedOperations; + ModelToINetworkConverter modelConverter(options.GetBackends(), + model, + unsupportedOperations); + + if (modelConverter.GetConversionResult() != ConversionResult::Success) + { + FailPrepareModel(ErrorStatus::GENERAL_FAILURE, "ModelToINetworkConverter failed", cb); + return ErrorStatus::NONE; + } + + // Optimize the network + armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr); + armnn::OptimizerOptions OptOptions; + OptOptions.m_ReduceFp32ToFp16 = float32ToFloat16; + + std::vector errMessages; + try + { + optNet = armnn::Optimize(*modelConverter.GetINetwork(), + options.GetBackends(), + runtime->GetDeviceSpec(), + OptOptions, + errMessages); + } + catch (armnn::Exception &e) + { + std::stringstream message; + message << "armnn::Exception (" << e.what() << ") caught from optimize."; + FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb); + return ErrorStatus::NONE; + } + + // Check that the optimized network is valid. + if (!optNet) + { + std::stringstream message; + message << "Invalid optimized network"; + for (const std::string& msg : errMessages) + { + message << "\n" << msg; + } + FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb); + return ErrorStatus::NONE; + } + + // Export the optimized network graph to a dot file if an output dump directory + // has been specified in the drivers' arguments. + ExportNetworkGraphToDotFile(*optNet, options.GetRequestInputsAndOutputsDumpDir(), + model); + + // Load it into the runtime. + armnn::NetworkId netId = 0; + try + { + if (runtime->LoadNetwork(netId, move(optNet)) != armnn::Status::Success) + { + return FailPrepareModel(ErrorStatus::GENERAL_FAILURE, "Network could not be loaded", cb); + } + } + catch (armnn::Exception& e) + { + std::stringstream message; + message << "armnn::Exception (" << e.what()<< ") caught from LoadNetwork."; + FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb); + return ErrorStatus::NONE; + } + + std::unique_ptr> preparedModel( + new ArmnnPreparedModel_1_2( + netId, + runtime.get(), + model, + options.GetRequestInputsAndOutputsDumpDir(), + options.IsGpuProfilingEnabled())); + + // Run a single 'dummy' inference of the model. This means that CL kernels will get compiled (and tuned if + // this is enabled) before the first 'real' inference which removes the overhead of the first inference. + if (!preparedModel->ExecuteWithDummyInputs()) + { + return FailPrepareModel(ErrorStatus::GENERAL_FAILURE, "Network could not be executed", cb); + } + + if (clTunedParameters && + options.GetClTunedParametersMode() == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters) + { + // Now that we've done one inference the CL kernel parameters will have been tuned, so save the updated file. + try + { + clTunedParameters->Save(options.GetClTunedParametersFile().c_str()); + } + catch (const armnn::Exception& error) + { + ALOGE("ArmnnDriverImpl::prepareModel: Failed to save CL tuned parameters file '%s': %s", + options.GetClTunedParametersFile().c_str(), error.what()); + } + } + + NotifyCallbackAndCheck(cb, ErrorStatus::NONE, preparedModel.release()); + + return ErrorStatus::NONE; +} + +Return ArmnnDriverImpl::getCapabilities_1_2(const armnn::IRuntimePtr& runtime, + V1_2::IDevice::getCapabilities_1_2_cb cb) +{ + ALOGV("hal_1_2::ArmnnDriverImpl::getCapabilities()"); + + V1_2::Capabilities capabilities; + + if (runtime) + { + capabilities.relaxedFloat32toFloat16PerformanceScalar.execTime = + ParseSystemProperty(g_RelaxedFloat32toFloat16PerformanceExecTime, .1f); + + capabilities.relaxedFloat32toFloat16PerformanceTensor.execTime = + ParseSystemProperty(g_RelaxedFloat32toFloat16PerformanceExecTime, .1f); + + cb(ErrorStatus::NONE, capabilities); + } + else + { + capabilities.relaxedFloat32toFloat16PerformanceScalar.execTime = 0; + capabilities.relaxedFloat32toFloat16PerformanceTensor.execTime = 0; + + cb(ErrorStatus::DEVICE_UNAVAILABLE, capabilities); + } + + return Void(); +} + +} // namespace hal_1_2 +} // namespace armnn_driver \ No newline at end of file -- cgit v1.2.1