blob: 97cfa5de2c5c40af95350fd7df512c270abaeab8 [file] [log] [blame]
Mike Kellyb5fdf382019-06-11 16:35:25 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "ArmnnDriverImpl.hpp"
7#include "../ArmnnPreparedModel_1_2.hpp"
8#include "../ModelToINetworkConverter.hpp"
9#include "../SystemPropertiesUtils.hpp"
10
11#include <log/log.h>
12
13namespace
14{
15
16const char *g_RelaxedFloat32toFloat16PerformanceExecTime = "ArmNN.relaxedFloat32toFloat16Performance.execTime";
17void NotifyCallbackAndCheck(const sp<V1_2::IPreparedModelCallback>& callback,
18 ErrorStatus errorStatus,
19 const sp<V1_2::IPreparedModel>& preparedModelPtr)
20{
21 Return<void> returned = callback->notify(errorStatus, preparedModelPtr);
22 // This check is required, if the callback fails and it isn't checked it will bring down the service
23 if (!returned.isOk())
24 {
25 ALOGE("ArmnnDriverImpl::prepareModel: hidl callback failed to return properly: %s ",
26 returned.description().c_str());
27 }
28}
29
30Return<ErrorStatus> FailPrepareModel(ErrorStatus error,
31 const std::string& message,
32 const sp<V1_2::IPreparedModelCallback>& callback)
33{
34 ALOGW("ArmnnDriverImpl::prepareModel: %s", message.c_str());
35 NotifyCallbackAndCheck(callback, error, nullptr);
36 return error;
37}
38
39} // anonymous namespace
40
41namespace armnn_driver
42{
43namespace hal_1_2
44{
45
46Return<ErrorStatus> ArmnnDriverImpl::prepareArmnnModel_1_2(const armnn::IRuntimePtr& runtime,
47 const armnn::IGpuAccTunedParametersPtr& clTunedParameters,
48 const DriverOptions& options,
49 const V1_2::Model& model,
50 const sp<V1_2::IPreparedModelCallback>& cb,
51 bool float32ToFloat16)
52{
53 ALOGV("ArmnnDriverImpl::prepareModel()");
54
55 if (cb.get() == nullptr)
56 {
57 ALOGW("ArmnnDriverImpl::prepareModel: Invalid callback passed to prepareModel");
58 return ErrorStatus::INVALID_ARGUMENT;
59 }
60
61 if (!runtime)
62 {
63 return FailPrepareModel(ErrorStatus::DEVICE_UNAVAILABLE, "Device unavailable", cb);
64 }
65
66 if (!android::nn::validateModel(model))
67 {
68 return FailPrepareModel(ErrorStatus::INVALID_ARGUMENT, "Invalid model passed as input", cb);
69 }
70
71 // Deliberately ignore any unsupported operations requested by the options -
72 // at this point we're being asked to prepare a model that we've already declared support for
73 // and the operation indices may be different to those in getSupportedOperations anyway.
74 std::set<unsigned int> unsupportedOperations;
75 ModelToINetworkConverter<HalPolicy> modelConverter(options.GetBackends(),
76 model,
77 unsupportedOperations);
78
79 if (modelConverter.GetConversionResult() != ConversionResult::Success)
80 {
81 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, "ModelToINetworkConverter failed", cb);
82 return ErrorStatus::NONE;
83 }
84
85 // Optimize the network
86 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
87 armnn::OptimizerOptions OptOptions;
88 OptOptions.m_ReduceFp32ToFp16 = float32ToFloat16;
89
90 std::vector<std::string> errMessages;
91 try
92 {
93 optNet = armnn::Optimize(*modelConverter.GetINetwork(),
94 options.GetBackends(),
95 runtime->GetDeviceSpec(),
96 OptOptions,
97 errMessages);
98 }
99 catch (armnn::Exception &e)
100 {
101 std::stringstream message;
102 message << "armnn::Exception (" << e.what() << ") caught from optimize.";
103 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
104 return ErrorStatus::NONE;
105 }
106
107 // Check that the optimized network is valid.
108 if (!optNet)
109 {
110 std::stringstream message;
111 message << "Invalid optimized network";
112 for (const std::string& msg : errMessages)
113 {
114 message << "\n" << msg;
115 }
116 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
117 return ErrorStatus::NONE;
118 }
119
120 // Export the optimized network graph to a dot file if an output dump directory
121 // has been specified in the drivers' arguments.
122 ExportNetworkGraphToDotFile<hal_1_2::HalPolicy::Model>(*optNet, options.GetRequestInputsAndOutputsDumpDir(),
123 model);
124
125 // Load it into the runtime.
126 armnn::NetworkId netId = 0;
127 try
128 {
129 if (runtime->LoadNetwork(netId, move(optNet)) != armnn::Status::Success)
130 {
131 return FailPrepareModel(ErrorStatus::GENERAL_FAILURE, "Network could not be loaded", cb);
132 }
133 }
134 catch (armnn::Exception& e)
135 {
136 std::stringstream message;
137 message << "armnn::Exception (" << e.what()<< ") caught from LoadNetwork.";
138 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
139 return ErrorStatus::NONE;
140 }
141
142 std::unique_ptr<ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>> preparedModel(
143 new ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>(
144 netId,
145 runtime.get(),
146 model,
147 options.GetRequestInputsAndOutputsDumpDir(),
148 options.IsGpuProfilingEnabled()));
149
150 // Run a single 'dummy' inference of the model. This means that CL kernels will get compiled (and tuned if
151 // this is enabled) before the first 'real' inference which removes the overhead of the first inference.
152 if (!preparedModel->ExecuteWithDummyInputs())
153 {
154 return FailPrepareModel(ErrorStatus::GENERAL_FAILURE, "Network could not be executed", cb);
155 }
156
157 if (clTunedParameters &&
158 options.GetClTunedParametersMode() == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters)
159 {
160 // Now that we've done one inference the CL kernel parameters will have been tuned, so save the updated file.
161 try
162 {
163 clTunedParameters->Save(options.GetClTunedParametersFile().c_str());
164 }
165 catch (const armnn::Exception& error)
166 {
167 ALOGE("ArmnnDriverImpl::prepareModel: Failed to save CL tuned parameters file '%s': %s",
168 options.GetClTunedParametersFile().c_str(), error.what());
169 }
170 }
171
172 NotifyCallbackAndCheck(cb, ErrorStatus::NONE, preparedModel.release());
173
174 return ErrorStatus::NONE;
175}
176
177Return<void> ArmnnDriverImpl::getCapabilities_1_2(const armnn::IRuntimePtr& runtime,
178 V1_2::IDevice::getCapabilities_1_2_cb cb)
179{
180 ALOGV("hal_1_2::ArmnnDriverImpl::getCapabilities()");
181
182 V1_2::Capabilities capabilities;
183
184 if (runtime)
185 {
186 capabilities.relaxedFloat32toFloat16PerformanceScalar.execTime =
187 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformanceExecTime, .1f);
188
189 capabilities.relaxedFloat32toFloat16PerformanceTensor.execTime =
190 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformanceExecTime, .1f);
191
192 cb(ErrorStatus::NONE, capabilities);
193 }
194 else
195 {
196 capabilities.relaxedFloat32toFloat16PerformanceScalar.execTime = 0;
197 capabilities.relaxedFloat32toFloat16PerformanceTensor.execTime = 0;
198
199 cb(ErrorStatus::DEVICE_UNAVAILABLE, capabilities);
200 }
201
202 return Void();
203}
204
205} // namespace hal_1_2
206} // namespace armnn_driver