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