blob: 62c6b038da14af6a1ebf65206bbd9d1fbdaccd1d [file] [log] [blame]
David Beck1b61be52018-11-08 09:19:14 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "ClBackendContext.hpp"
Derek Lamberti836b27b2019-11-20 10:51:57 +00007#include "ClContextControl.hpp"
Derek Lamberti08446972019-11-26 16:38:31 +00008
9#include <armnn/Logging.hpp>
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010010#include <armnn/utility/Assert.hpp>
Jan Eilersbb446e52020-04-02 13:56:54 +010011#include <armnn/utility/PolymorphicDowncast.hpp>
Derek Lamberti08446972019-11-26 16:38:31 +000012
David Beck1b61be52018-11-08 09:19:14 +000013#include <arm_compute/core/CL/OpenCL.h>
14#include <arm_compute/core/CL/CLKernelLibrary.h>
15#include <arm_compute/runtime/CL/CLScheduler.h>
Derek Lamberti836b27b2019-11-20 10:51:57 +000016#include <arm_compute/runtime/CL/CLTunerTypes.h>
17
David Beck1b61be52018-11-08 09:19:14 +000018namespace armnn
19{
20
21struct ClBackendContext::ClContextControlWrapper
22{
Mike Kelly21cf67a2022-11-22 16:16:01 +000023 ClContextControlWrapper() {}
24
25 bool IsInitialised()
26 {
27 return m_Initialised;
28 }
29
30 void Init(arm_compute::CLTuner* tuner,
31 arm_compute::CLGEMMHeuristicsHandle* heuristicsHandle,
32 bool profilingEnabled)
33 {
34 m_ClContextControl = ClContextControl(tuner, heuristicsHandle, profilingEnabled);
35 m_Initialised = true;
36 }
David Beck1b61be52018-11-08 09:19:14 +000037
38 bool Sync()
39 {
David Beck1b61be52018-11-08 09:19:14 +000040 if (arm_compute::CLScheduler::get().context()() != NULL)
41 {
42 // Waits for all queued CL requests to finish before unloading the network they may be using.
43 try
44 {
45 // Coverity fix: arm_compute::CLScheduler::sync() may throw an exception of type cl::Error.
46 arm_compute::CLScheduler::get().sync();
47 }
48 catch (const cl::Error&)
49 {
Derek Lamberti08446972019-11-26 16:38:31 +000050 ARMNN_LOG(warning) << "Runtime::UnloadNetwork(): an error occurred while waiting for "
51 "the queued CL requests to finish";
David Beck1b61be52018-11-08 09:19:14 +000052 return false;
53 }
54 }
Aron Virginas-Tard46e6472018-11-16 10:26:23 +000055
David Beck1b61be52018-11-08 09:19:14 +000056 return true;
57 }
58
59 void ClearClCache()
60 {
David Beck1b61be52018-11-08 09:19:14 +000061 if (arm_compute::CLScheduler::get().context()() != NULL)
62 {
63 // There are no loaded networks left, so clear the CL cache to free up memory
64 m_ClContextControl.ClearClCache();
Mike Kelly21cf67a2022-11-22 16:16:01 +000065 m_Initialised = false;
David Beck1b61be52018-11-08 09:19:14 +000066 }
David Beck1b61be52018-11-08 09:19:14 +000067 }
68
Mike Kelly21cf67a2022-11-22 16:16:01 +000069private:
70 bool m_Initialised;
David Beck1b61be52018-11-08 09:19:14 +000071 ClContextControl m_ClContextControl;
Mike Kelly21cf67a2022-11-22 16:16:01 +000072
David Beck1b61be52018-11-08 09:19:14 +000073};
74
Mike Kelly21cf67a2022-11-22 16:16:01 +000075/**
76 * Returns a shared_ptr to the CLContextControlWrapper. This wraps the CLContextControl and ensures that we only create
77 * and use one at a time.
78 */
79std::shared_ptr<ClBackendContext::ClContextControlWrapper> ClBackendContext::Get()
80{
81 static std::shared_ptr<ClBackendContext::ClContextControlWrapper> instance
82 = std::make_shared<ClBackendContext::ClContextControlWrapper>();
83 // Instantiated on first use.
84 return instance;
85}
86
Derek Lamberti836b27b2019-11-20 10:51:57 +000087std::string LowerString(std::string value)
88{
89 std::transform(value.begin(), value.end(), value.begin(),
90 [](unsigned char c){ return std::tolower(c); });
91
92 return value;
93}
94
95enum class TuningLevel
96{
97 None,
98 Rapid,
99 Normal,
100 Exhaustive
101};
102
103
104TuningLevel ParseTuningLevel(const BackendOptions::Var& value, TuningLevel defaultValue)
105{
106 if (value.IsInt())
107 {
alered01a7227ac2020-05-07 14:58:29 +0100108 int v = value.AsInt();
Derek Lamberti836b27b2019-11-20 10:51:57 +0000109 if (v > static_cast<int>(TuningLevel::Exhaustive) ||
110 v < static_cast<int>(TuningLevel::None))
111 {
112 ARMNN_LOG(warning) << "Invalid GpuAcc tuning level ("<< v << ") selected. "
113 "Using default(" << static_cast<int>(defaultValue) << ")";
114 } else
115 {
116 return static_cast<TuningLevel>(v);
117 }
118 }
119 return defaultValue;
120}
121
122bool ParseBoolean(const BackendOptions::Var& value, bool defaultValue)
123{
124 if (value.IsBool())
125 {
126 return value.AsBool();
127 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000128 return defaultValue;
129}
130
131std::string ParseFile(const BackendOptions::Var& value, std::string defaultValue)
132{
133 if (value.IsString())
134 {
135 return value.AsString();
136 }
137 return defaultValue;
138}
139
Derek Lamberti5c510f82020-02-11 12:56:52 +0000140void ConfigureTuner(arm_compute::CLTuner &tuner, TuningLevel level)
141{
142 tuner.set_tune_new_kernels(true); // Turn on tuning initially.
143
144 switch (level)
145 {
146 case TuningLevel::Rapid:
Jan Eilers2cd18472020-12-15 10:42:38 +0000147 ARMNN_LOG(info) << "Gpu tuning is activated. TuningLevel: Rapid (1)";
Derek Lamberti5c510f82020-02-11 12:56:52 +0000148 tuner.set_tuner_mode(arm_compute::CLTunerMode::RAPID);
149 break;
150 case TuningLevel::Normal:
Jan Eilers2cd18472020-12-15 10:42:38 +0000151 ARMNN_LOG(info) << "Gpu tuning is activated. TuningLevel: Normal (2)";
Derek Lamberti5c510f82020-02-11 12:56:52 +0000152 tuner.set_tuner_mode(arm_compute::CLTunerMode::NORMAL);
153 break;
154 case TuningLevel::Exhaustive:
Jan Eilers2cd18472020-12-15 10:42:38 +0000155 ARMNN_LOG(info) << "Gpu tuning is activated. TuningLevel: Exhaustive (3)";
Derek Lamberti5c510f82020-02-11 12:56:52 +0000156 tuner.set_tuner_mode(arm_compute::CLTunerMode::EXHAUSTIVE);
157 break;
158 case TuningLevel::None:
159 default:
160 tuner.set_tune_new_kernels(false); // Turn off tuning. Set to "use" only mode.
161 break;
162 }
163}
164
David Beck1b61be52018-11-08 09:19:14 +0000165ClBackendContext::ClBackendContext(const IRuntime::CreationOptions& options)
166 : IBackendContext(options)
Derek Lamberti5c510f82020-02-11 12:56:52 +0000167 , m_TuningFile()
David Beck1b61be52018-11-08 09:19:14 +0000168{
Derek Lamberti836b27b2019-11-20 10:51:57 +0000169 bool kernelProfiling = options.m_EnableGpuProfiling;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000170
Derek Lamberti836b27b2019-11-20 10:51:57 +0000171 arm_compute::CLTuner* tuner = nullptr;
Finn Williams40646322021-02-11 16:16:42 +0000172 arm_compute::CLGEMMHeuristicsHandle* mlgoTuner = nullptr;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000173 bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
Mike Kelly21cf67a2022-11-22 16:16:01 +0000174
Derek Lambertief7e6b62020-02-04 14:49:16 +0000175 if (useLegacyTunerAPI)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000176 {
Jan Eilersbb446e52020-04-02 13:56:54 +0100177 auto clTunerParams = PolymorphicDowncast<ClTunedParameters*>(
Derek Lambertief7e6b62020-02-04 14:49:16 +0000178 options.m_GpuAccTunedParameters.get());
Derek Lamberti5c510f82020-02-11 12:56:52 +0000179 tuner = &clTunerParams->m_Tuner;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000180
Derek Lamberti5c510f82020-02-11 12:56:52 +0000181 if (tuner)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000182 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000183 auto ConvertTuningLevel = [](IGpuAccTunedParameters::TuningLevel level,
184 armnn::IGpuAccTunedParameters::Mode mode)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000185 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000186 if (mode == armnn::IGpuAccTunedParameters::Mode::UseTunedParameters)
187 {
188 return TuningLevel::None;
189 }
190
Derek Lambertief7e6b62020-02-04 14:49:16 +0000191 switch(level)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000192 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000193 case IGpuAccTunedParameters::TuningLevel::Rapid:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000194 return TuningLevel::Rapid;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000195 case IGpuAccTunedParameters::TuningLevel::Normal:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000196 return TuningLevel::Normal;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000197 case IGpuAccTunedParameters::TuningLevel::Exhaustive:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000198 return TuningLevel::Exhaustive;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000199 default:
200 {
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100201 ARMNN_ASSERT_MSG(false, "Tuning level not recognised.");
Derek Lamberti5c510f82020-02-11 12:56:52 +0000202 return TuningLevel::None;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000203 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000204 }
Derek Lambertief7e6b62020-02-04 14:49:16 +0000205 };
Derek Lamberti836b27b2019-11-20 10:51:57 +0000206
Derek Lamberti5c510f82020-02-11 12:56:52 +0000207 TuningLevel tuningLevel = ConvertTuningLevel(clTunerParams->m_TuningLevel, clTunerParams->m_Mode);
208 ConfigureTuner(*tuner, tuningLevel);
Derek Lambertief7e6b62020-02-04 14:49:16 +0000209 }
210 }
211 else //New backend options API
212 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000213 const TuningLevel defaultTuningLevel = TuningLevel::None;
214 auto tuningLevel = defaultTuningLevel;
215
Derek Lambertief7e6b62020-02-04 14:49:16 +0000216 ParseOptions(options.m_BackendOptions, "GpuAcc", [&](std::string name, const BackendOptions::Var& value)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000217 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000218 if (name == "KernelProfilingEnabled")
219 {
220 kernelProfiling |= ParseBoolean(value, false);
221 } else if (name == "TuningFile")
222 {
223 m_TuningFile = ParseFile(value, "");
224 } else if (name == "TuningLevel")
225 {
226 tuningLevel = ParseTuningLevel(value, defaultTuningLevel);
227 }
Finn Williams40646322021-02-11 16:16:42 +0000228 else if (name == "MLGOTuningFilePath")
229 {
230 m_MLGOTuningFile = ParseFile(value, "");
231 }
Derek Lambertief7e6b62020-02-04 14:49:16 +0000232 });
Derek Lamberti836b27b2019-11-20 10:51:57 +0000233
Derek Lambertief7e6b62020-02-04 14:49:16 +0000234 // Create the tuner, in tuning mode initially.
235 m_Tuner = std::make_unique<arm_compute::CLTuner>(true);
236
Derek Lamberti5c510f82020-02-11 12:56:52 +0000237 ConfigureTuner(*(m_Tuner.get()), tuningLevel);
Derek Lambertief7e6b62020-02-04 14:49:16 +0000238
Stuart Taylor06ccd712022-03-15 17:03:58 +0000239 if (!m_TuningFile.empty())
Derek Lambertief7e6b62020-02-04 14:49:16 +0000240 {
Derek Lamberti836b27b2019-11-20 10:51:57 +0000241 try
242 {
Jan Eilers2cd18472020-12-15 10:42:38 +0000243 ARMNN_LOG(info) << "Loading Gpu tuning data from file: " << m_TuningFile;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000244 m_Tuner->load_from_file(m_TuningFile.c_str());
alered01a7227ac2020-05-07 14:58:29 +0100245 }
246 catch (const std::exception& e)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000247 {
Stuart Taylor06ccd712022-03-15 17:03:58 +0000248 // Warn if not tuning, otherwise tuning will generate new params
249 if (tuningLevel == TuningLevel::None)
250 {
251 ARMNN_LOG(warning) << "Could not load GpuAcc tuner data file.";
252 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000253 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000254 }
Finn Williams40646322021-02-11 16:16:42 +0000255
256 if (!m_MLGOTuningFile.empty())
257 {
258 try
259 {
260 ARMNN_LOG(info) << "Loading Gpu MLGO tuning data from file: " << m_TuningFile;
261 if(m_MLGOTuner.reload_from_file(m_MLGOTuningFile.c_str()))
262 {
263 mlgoTuner = &m_MLGOTuner;
264 }
265 }
266 catch (const std::exception& e)
267 {
268 ARMNN_LOG(warning) << "Could not load GpuAcc MLGO tuner data file.";
269 }
270 }
271
alered01a7227ac2020-05-07 14:58:29 +0100272 tuner = m_Tuner.get();
Derek Lamberti836b27b2019-11-20 10:51:57 +0000273 }
274
Mike Kelly21cf67a2022-11-22 16:16:01 +0000275 m_ClContextControlWrapper = Get();
276
277 if (!m_ClContextControlWrapper->IsInitialised())
278 {
279 m_ClContextControlWrapper->Init(tuner, mlgoTuner, kernelProfiling);
280 }
David Beck1b61be52018-11-08 09:19:14 +0000281}
282
283bool ClBackendContext::BeforeLoadNetwork(NetworkId)
284{
285 return true;
286}
287
288bool ClBackendContext::AfterLoadNetwork(NetworkId networkId)
289{
290 {
291 std::lock_guard<std::mutex> lockGuard(m_Mutex);
292 m_NetworkIds.insert(networkId);
293 }
294 return true;
295}
296
297bool ClBackendContext::BeforeUnloadNetwork(NetworkId)
298{
299 return m_ClContextControlWrapper->Sync();
300}
301
302bool ClBackendContext::AfterUnloadNetwork(NetworkId networkId)
303{
304 bool clearCache = false;
305 {
306 std::lock_guard<std::mutex> lockGuard(m_Mutex);
307 m_NetworkIds.erase(networkId);
308 clearCache = m_NetworkIds.empty();
309 }
310
311 if (clearCache)
312 {
313 m_ClContextControlWrapper->ClearClCache();
314 }
315
316 return true;
317}
318
Narumol Prangnawaratec5463d2022-02-04 17:50:20 +0000319bool ClBackendContext::AfterEnqueueWorkload(NetworkId)
320{
321 return m_ClContextControlWrapper->Sync();
322}
323
David Beck1b61be52018-11-08 09:19:14 +0000324ClBackendContext::~ClBackendContext()
325{
Derek Lamberti836b27b2019-11-20 10:51:57 +0000326 if (m_Tuner && !m_TuningFile.empty())
327 {
328 try
329 {
330 m_Tuner->save_to_file(m_TuningFile.c_str());
331 }
332 catch(const std::exception& e)
333 {
334 ARMNN_LOG(warning) << "Could not save GpuAcc tuner data to file " << m_TuningFile;
335 }
336 }
David Beck1b61be52018-11-08 09:19:14 +0000337}
338
339} // namespace armnn