blob: 7309c2a121849dc4e37ac3e1a20c87e97b822604 [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
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +010016const char *g_RelaxedFloat32toFloat16PerformanceExecTime = "ArmNN.relaxedFloat32toFloat16Performance.execTime";
FinnWilliamsArmdf655ee2019-07-24 16:04:18 +010017const char *g_RelaxedFloat32toFloat16PerformancePowerUsage = "ArmNN.relaxedFloat32toFloat16Performance.powerUsage";
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +010018
19const char *g_OperandTypeTensorFloat32PerformanceExecTime = "Armnn.operandTypeTensorFloat32Performance.execTime";
20const char *g_OperandTypeTensorFloat32PerformancePowerUsage = "Armnn.operandTypeTensorFloat32Performance.powerUsage";
21
22const char *g_OperandTypeFloat32PerformanceExecTime = "Armnn.operandTypeFloat32Performance.execTime";
23const char *g_OperandTypeFloat32PerformancePowerUsage = "Armnn.operandTypeFloat32Performance.powerUsage";
24
25const char *g_OperandTypeTensorFloat16PerformanceExecTime = "Armnn.operandTypeTensorFloat16Performance.execTime";
26const char *g_OperandTypeTensorFloat16PerformancePowerUsage = "Armnn.operandTypeTensorFloat16Performance.powerUsage";
27
28const char *g_OperandTypeFloat16PerformanceExecTime = "Armnn.operandTypeFloat16Performance.execTime";
29const char *g_OperandTypeFloat16PerformancePowerUsage = "Armnn.operandTypeFloat16Performance.powerUsage";
30
31const char *g_OperandTypeTensorQuant8AsymmPerformanceExecTime =
32 "Armnn.operandTypeTensorQuant8AsymmPerformance.execTime";
33const char *g_OperandTypeTensorQuant8AsymmPerformancePowerUsage =
34 "Armnn.operandTypeTensorQuant8AsymmPerformance.powerUsage";
35
36const char *g_OperandTypeTensorQuant16SymmPerformanceExecTime =
37 "Armnn.operandTypeTensorQuant16SymmPerformance.execTime";
38const char *g_OperandTypeTensorQuant16SymmPerformancePowerUsage =
39 "Armnn.operandTypeTensorQuant16SymmPerformance.powerUsage";
40
Pablo Tellofb45e2f2019-10-18 16:51:57 +010041const char *g_OperandTypeTensorQuant8SymmPerformanceExecTime =
42 "Armnn.operandTypeTensorQuant8SymmPerformance.execTime";
43const char *g_OperandTypeTensorQuant8SymmPerformancePowerUsage =
44 "Armnn.operandTypeTensorQuant8SymmPerformance.powerUsage";
45
46
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +010047const char *g_OperandTypeTensorInt32PerformanceExecTime = "Armnn.operandTypeTensorInt32Performance.execTime";
48const char *g_OperandTypeTensorInt32PerformancePowerUsage = "Armnn.operandTypeTensorInt32Performance.powerUsage";
49
50const char *g_OperandTypeInt32PerformanceExecTime = "Armnn.operandTypeInt32Performance.execTime";
51const char *g_OperandTypeInt32PerformancePowerUsage = "Armnn.operandTypeInt32Performance.powerUsage";
52
53
Mike Kellyb5fdf382019-06-11 16:35:25 +010054void NotifyCallbackAndCheck(const sp<V1_2::IPreparedModelCallback>& callback,
55 ErrorStatus errorStatus,
56 const sp<V1_2::IPreparedModel>& preparedModelPtr)
57{
Ferran Balaguerb2397fd2019-07-25 12:12:39 +010058 Return<void> returned = callback->notify_1_2(errorStatus, preparedModelPtr);
Mike Kellyb5fdf382019-06-11 16:35:25 +010059 // This check is required, if the callback fails and it isn't checked it will bring down the service
60 if (!returned.isOk())
61 {
62 ALOGE("ArmnnDriverImpl::prepareModel: hidl callback failed to return properly: %s ",
63 returned.description().c_str());
64 }
65}
66
67Return<ErrorStatus> FailPrepareModel(ErrorStatus error,
68 const std::string& message,
69 const sp<V1_2::IPreparedModelCallback>& callback)
70{
71 ALOGW("ArmnnDriverImpl::prepareModel: %s", message.c_str());
72 NotifyCallbackAndCheck(callback, error, nullptr);
73 return error;
74}
75
76} // anonymous namespace
77
78namespace armnn_driver
79{
80namespace hal_1_2
81{
82
83Return<ErrorStatus> ArmnnDriverImpl::prepareArmnnModel_1_2(const armnn::IRuntimePtr& runtime,
84 const armnn::IGpuAccTunedParametersPtr& clTunedParameters,
85 const DriverOptions& options,
86 const V1_2::Model& model,
87 const sp<V1_2::IPreparedModelCallback>& cb,
88 bool float32ToFloat16)
89{
Matteo Martincigh0bd89a82019-07-02 16:53:10 +010090 ALOGV("ArmnnDriverImpl::prepareArmnnModel_1_2()");
Mike Kellyb5fdf382019-06-11 16:35:25 +010091
92 if (cb.get() == nullptr)
93 {
94 ALOGW("ArmnnDriverImpl::prepareModel: Invalid callback passed to prepareModel");
95 return ErrorStatus::INVALID_ARGUMENT;
96 }
97
98 if (!runtime)
99 {
100 return FailPrepareModel(ErrorStatus::DEVICE_UNAVAILABLE, "Device unavailable", cb);
101 }
102
103 if (!android::nn::validateModel(model))
104 {
105 return FailPrepareModel(ErrorStatus::INVALID_ARGUMENT, "Invalid model passed as input", cb);
106 }
107
108 // Deliberately ignore any unsupported operations requested by the options -
109 // at this point we're being asked to prepare a model that we've already declared support for
110 // and the operation indices may be different to those in getSupportedOperations anyway.
111 std::set<unsigned int> unsupportedOperations;
112 ModelToINetworkConverter<HalPolicy> modelConverter(options.GetBackends(),
113 model,
114 unsupportedOperations);
115
116 if (modelConverter.GetConversionResult() != ConversionResult::Success)
117 {
118 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, "ModelToINetworkConverter failed", cb);
119 return ErrorStatus::NONE;
120 }
121
122 // Optimize the network
123 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
124 armnn::OptimizerOptions OptOptions;
125 OptOptions.m_ReduceFp32ToFp16 = float32ToFloat16;
126
127 std::vector<std::string> errMessages;
128 try
129 {
130 optNet = armnn::Optimize(*modelConverter.GetINetwork(),
131 options.GetBackends(),
132 runtime->GetDeviceSpec(),
133 OptOptions,
134 errMessages);
135 }
136 catch (armnn::Exception &e)
137 {
138 std::stringstream message;
139 message << "armnn::Exception (" << e.what() << ") caught from optimize.";
140 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
141 return ErrorStatus::NONE;
142 }
143
144 // Check that the optimized network is valid.
145 if (!optNet)
146 {
147 std::stringstream message;
148 message << "Invalid optimized network";
149 for (const std::string& msg : errMessages)
150 {
151 message << "\n" << msg;
152 }
153 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
154 return ErrorStatus::NONE;
155 }
156
157 // Export the optimized network graph to a dot file if an output dump directory
158 // has been specified in the drivers' arguments.
159 ExportNetworkGraphToDotFile<hal_1_2::HalPolicy::Model>(*optNet, options.GetRequestInputsAndOutputsDumpDir(),
160 model);
161
162 // Load it into the runtime.
163 armnn::NetworkId netId = 0;
164 try
165 {
166 if (runtime->LoadNetwork(netId, move(optNet)) != armnn::Status::Success)
167 {
168 return FailPrepareModel(ErrorStatus::GENERAL_FAILURE, "Network could not be loaded", cb);
169 }
170 }
171 catch (armnn::Exception& e)
172 {
173 std::stringstream message;
174 message << "armnn::Exception (" << e.what()<< ") caught from LoadNetwork.";
175 FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
176 return ErrorStatus::NONE;
177 }
178
179 std::unique_ptr<ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>> preparedModel(
180 new ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>(
181 netId,
182 runtime.get(),
183 model,
184 options.GetRequestInputsAndOutputsDumpDir(),
185 options.IsGpuProfilingEnabled()));
186
187 // Run a single 'dummy' inference of the model. This means that CL kernels will get compiled (and tuned if
188 // this is enabled) before the first 'real' inference which removes the overhead of the first inference.
189 if (!preparedModel->ExecuteWithDummyInputs())
190 {
191 return FailPrepareModel(ErrorStatus::GENERAL_FAILURE, "Network could not be executed", cb);
192 }
193
194 if (clTunedParameters &&
195 options.GetClTunedParametersMode() == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters)
196 {
197 // Now that we've done one inference the CL kernel parameters will have been tuned, so save the updated file.
198 try
199 {
200 clTunedParameters->Save(options.GetClTunedParametersFile().c_str());
201 }
202 catch (const armnn::Exception& error)
203 {
204 ALOGE("ArmnnDriverImpl::prepareModel: Failed to save CL tuned parameters file '%s': %s",
205 options.GetClTunedParametersFile().c_str(), error.what());
206 }
207 }
208
209 NotifyCallbackAndCheck(cb, ErrorStatus::NONE, preparedModel.release());
210
211 return ErrorStatus::NONE;
212}
213
214Return<void> ArmnnDriverImpl::getCapabilities_1_2(const armnn::IRuntimePtr& runtime,
215 V1_2::IDevice::getCapabilities_1_2_cb cb)
216{
217 ALOGV("hal_1_2::ArmnnDriverImpl::getCapabilities()");
218
219 V1_2::Capabilities capabilities;
220
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100221 float defaultValue = .1f;
222
Mike Kellyb5fdf382019-06-11 16:35:25 +0100223 if (runtime)
224 {
225 capabilities.relaxedFloat32toFloat16PerformanceScalar.execTime =
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100226 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformanceExecTime, defaultValue);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100227
FinnWilliamsArmdf655ee2019-07-24 16:04:18 +0100228 capabilities.relaxedFloat32toFloat16PerformanceTensor.powerUsage =
229 ParseSystemProperty(g_RelaxedFloat32toFloat16PerformancePowerUsage, defaultValue);
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100230
231 // Set the base value for all operand types
232 capabilities.operandPerformance = nonExtensionOperandPerformance({FLT_MAX, FLT_MAX});
233
234 // Load supported operand types
235 update(&capabilities.operandPerformance, OperandType::TENSOR_FLOAT32,
236 {
237 .execTime = ParseSystemProperty(g_OperandTypeTensorFloat32PerformanceExecTime, defaultValue),
238 .powerUsage = ParseSystemProperty(g_OperandTypeTensorFloat32PerformancePowerUsage, defaultValue)
239 });
240
241 update(&capabilities.operandPerformance, OperandType::FLOAT32,
242 {
243 .execTime = ParseSystemProperty(g_OperandTypeFloat32PerformanceExecTime, defaultValue),
244 .powerUsage = ParseSystemProperty(g_OperandTypeFloat32PerformancePowerUsage, defaultValue)
245 });
246
247 update(&capabilities.operandPerformance, OperandType::TENSOR_FLOAT16,
248 {
249 .execTime = ParseSystemProperty(g_OperandTypeTensorFloat16PerformanceExecTime, defaultValue),
250 .powerUsage = ParseSystemProperty(g_OperandTypeTensorFloat16PerformancePowerUsage, defaultValue)
251 });
252
253 update(&capabilities.operandPerformance, OperandType::FLOAT16,
254 {
255 .execTime = ParseSystemProperty(g_OperandTypeFloat16PerformanceExecTime, defaultValue),
256 .powerUsage = ParseSystemProperty(g_OperandTypeFloat16PerformancePowerUsage, defaultValue)
257 });
258
259 update(&capabilities.operandPerformance, OperandType::TENSOR_QUANT8_ASYMM,
260 {
261 .execTime = ParseSystemProperty(g_OperandTypeTensorQuant8AsymmPerformanceExecTime, defaultValue),
262 .powerUsage = ParseSystemProperty(g_OperandTypeTensorQuant8AsymmPerformancePowerUsage, defaultValue)
263 });
264
Pablo Tellofb45e2f2019-10-18 16:51:57 +0100265 update(&capabilities.operandPerformance, OperandType::TENSOR_QUANT8_SYMM,
266 {
267 .execTime = ParseSystemProperty(g_OperandTypeTensorQuant8SymmPerformanceExecTime, defaultValue),
268 .powerUsage = ParseSystemProperty(g_OperandTypeTensorQuant8SymmPerformancePowerUsage, defaultValue)
269 });
270
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100271 update(&capabilities.operandPerformance, OperandType::TENSOR_QUANT16_SYMM,
272 {
273 .execTime = ParseSystemProperty(g_OperandTypeTensorQuant16SymmPerformanceExecTime, defaultValue),
274 .powerUsage = ParseSystemProperty(g_OperandTypeTensorQuant16SymmPerformancePowerUsage, defaultValue)
275 });
276
277 update(&capabilities.operandPerformance, OperandType::TENSOR_INT32,
278 {
279 .execTime = ParseSystemProperty(g_OperandTypeTensorInt32PerformanceExecTime, defaultValue),
280 .powerUsage = ParseSystemProperty(g_OperandTypeTensorInt32PerformancePowerUsage, defaultValue)
281 });
282
283 update(&capabilities.operandPerformance, OperandType::INT32,
284 {
285 .execTime = ParseSystemProperty(g_OperandTypeInt32PerformanceExecTime, defaultValue),
286 .powerUsage = ParseSystemProperty(g_OperandTypeInt32PerformancePowerUsage, defaultValue)
287 });
Mike Kellyb5fdf382019-06-11 16:35:25 +0100288
289 cb(ErrorStatus::NONE, capabilities);
290 }
291 else
292 {
293 capabilities.relaxedFloat32toFloat16PerformanceScalar.execTime = 0;
294 capabilities.relaxedFloat32toFloat16PerformanceTensor.execTime = 0;
295
Ferran Balaguerd7c8eb92019-07-01 13:37:44 +0100296 // Set the base value for all operand types
297 capabilities.operandPerformance = nonExtensionOperandPerformance({0.f, 0.0f});
298
Mike Kellyb5fdf382019-06-11 16:35:25 +0100299 cb(ErrorStatus::DEVICE_UNAVAILABLE, capabilities);
300 }
301
302 return Void();
303}
304
305} // namespace hal_1_2
Matteo Martincigh0bd89a82019-07-02 16:53:10 +0100306} // namespace armnn_driver