blob: 125f01b6270f58c6c4eaa4081eab314aee09142d [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{
Derek Lamberti836b27b2019-11-20 10:51:57 +000023 ClContextControlWrapper(arm_compute::CLTuner* tuner,
David Beck1b61be52018-11-08 09:19:14 +000024 bool profilingEnabled)
Derek Lamberti836b27b2019-11-20 10:51:57 +000025 : m_ClContextControl(tuner, profilingEnabled)
David Beck1b61be52018-11-08 09:19:14 +000026 {}
27
28 bool Sync()
29 {
David Beck1b61be52018-11-08 09:19:14 +000030 if (arm_compute::CLScheduler::get().context()() != NULL)
31 {
32 // Waits for all queued CL requests to finish before unloading the network they may be using.
33 try
34 {
35 // Coverity fix: arm_compute::CLScheduler::sync() may throw an exception of type cl::Error.
36 arm_compute::CLScheduler::get().sync();
37 }
38 catch (const cl::Error&)
39 {
Derek Lamberti08446972019-11-26 16:38:31 +000040 ARMNN_LOG(warning) << "Runtime::UnloadNetwork(): an error occurred while waiting for "
41 "the queued CL requests to finish";
David Beck1b61be52018-11-08 09:19:14 +000042 return false;
43 }
44 }
Aron Virginas-Tard46e6472018-11-16 10:26:23 +000045
David Beck1b61be52018-11-08 09:19:14 +000046 return true;
47 }
48
49 void ClearClCache()
50 {
David Beck1b61be52018-11-08 09:19:14 +000051 if (arm_compute::CLScheduler::get().context()() != NULL)
52 {
53 // There are no loaded networks left, so clear the CL cache to free up memory
54 m_ClContextControl.ClearClCache();
55 }
David Beck1b61be52018-11-08 09:19:14 +000056 }
57
David Beck1b61be52018-11-08 09:19:14 +000058 ClContextControl m_ClContextControl;
59};
60
Derek Lamberti836b27b2019-11-20 10:51:57 +000061std::string LowerString(std::string value)
62{
63 std::transform(value.begin(), value.end(), value.begin(),
64 [](unsigned char c){ return std::tolower(c); });
65
66 return value;
67}
68
69enum class TuningLevel
70{
71 None,
72 Rapid,
73 Normal,
74 Exhaustive
75};
76
77
78TuningLevel ParseTuningLevel(const BackendOptions::Var& value, TuningLevel defaultValue)
79{
80 if (value.IsInt())
81 {
alered01a7227ac2020-05-07 14:58:29 +010082 int v = value.AsInt();
Derek Lamberti836b27b2019-11-20 10:51:57 +000083 if (v > static_cast<int>(TuningLevel::Exhaustive) ||
84 v < static_cast<int>(TuningLevel::None))
85 {
86 ARMNN_LOG(warning) << "Invalid GpuAcc tuning level ("<< v << ") selected. "
87 "Using default(" << static_cast<int>(defaultValue) << ")";
88 } else
89 {
90 return static_cast<TuningLevel>(v);
91 }
92 }
93 return defaultValue;
94}
95
96bool ParseBoolean(const BackendOptions::Var& value, bool defaultValue)
97{
98 if (value.IsBool())
99 {
100 return value.AsBool();
101 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000102 return defaultValue;
103}
104
105std::string ParseFile(const BackendOptions::Var& value, std::string defaultValue)
106{
107 if (value.IsString())
108 {
109 return value.AsString();
110 }
111 return defaultValue;
112}
113
Derek Lamberti5c510f82020-02-11 12:56:52 +0000114void ConfigureTuner(arm_compute::CLTuner &tuner, TuningLevel level)
115{
116 tuner.set_tune_new_kernels(true); // Turn on tuning initially.
117
118 switch (level)
119 {
120 case TuningLevel::Rapid:
Jan Eilers2cd18472020-12-15 10:42:38 +0000121 ARMNN_LOG(info) << "Gpu tuning is activated. TuningLevel: Rapid (1)";
Derek Lamberti5c510f82020-02-11 12:56:52 +0000122 tuner.set_tuner_mode(arm_compute::CLTunerMode::RAPID);
123 break;
124 case TuningLevel::Normal:
Jan Eilers2cd18472020-12-15 10:42:38 +0000125 ARMNN_LOG(info) << "Gpu tuning is activated. TuningLevel: Normal (2)";
Derek Lamberti5c510f82020-02-11 12:56:52 +0000126 tuner.set_tuner_mode(arm_compute::CLTunerMode::NORMAL);
127 break;
128 case TuningLevel::Exhaustive:
Jan Eilers2cd18472020-12-15 10:42:38 +0000129 ARMNN_LOG(info) << "Gpu tuning is activated. TuningLevel: Exhaustive (3)";
Derek Lamberti5c510f82020-02-11 12:56:52 +0000130 tuner.set_tuner_mode(arm_compute::CLTunerMode::EXHAUSTIVE);
131 break;
132 case TuningLevel::None:
133 default:
134 tuner.set_tune_new_kernels(false); // Turn off tuning. Set to "use" only mode.
135 break;
136 }
137}
138
David Beck1b61be52018-11-08 09:19:14 +0000139ClBackendContext::ClBackendContext(const IRuntime::CreationOptions& options)
140 : IBackendContext(options)
Derek Lamberti5c510f82020-02-11 12:56:52 +0000141 , m_TuningFile()
David Beck1b61be52018-11-08 09:19:14 +0000142{
Derek Lamberti836b27b2019-11-20 10:51:57 +0000143 bool kernelProfiling = options.m_EnableGpuProfiling;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000144
Derek Lamberti836b27b2019-11-20 10:51:57 +0000145 arm_compute::CLTuner* tuner = nullptr;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000146 bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
147 if (useLegacyTunerAPI)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000148 {
Jan Eilersbb446e52020-04-02 13:56:54 +0100149 auto clTunerParams = PolymorphicDowncast<ClTunedParameters*>(
Derek Lambertief7e6b62020-02-04 14:49:16 +0000150 options.m_GpuAccTunedParameters.get());
Derek Lamberti5c510f82020-02-11 12:56:52 +0000151 tuner = &clTunerParams->m_Tuner;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000152
Derek Lamberti5c510f82020-02-11 12:56:52 +0000153 if (tuner)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000154 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000155 auto ConvertTuningLevel = [](IGpuAccTunedParameters::TuningLevel level,
156 armnn::IGpuAccTunedParameters::Mode mode)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000157 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000158 if (mode == armnn::IGpuAccTunedParameters::Mode::UseTunedParameters)
159 {
160 return TuningLevel::None;
161 }
162
Derek Lambertief7e6b62020-02-04 14:49:16 +0000163 switch(level)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000164 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000165 case IGpuAccTunedParameters::TuningLevel::Rapid:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000166 return TuningLevel::Rapid;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000167 case IGpuAccTunedParameters::TuningLevel::Normal:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000168 return TuningLevel::Normal;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000169 case IGpuAccTunedParameters::TuningLevel::Exhaustive:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000170 return TuningLevel::Exhaustive;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000171 default:
172 {
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100173 ARMNN_ASSERT_MSG(false, "Tuning level not recognised.");
Derek Lamberti5c510f82020-02-11 12:56:52 +0000174 return TuningLevel::None;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000175 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000176 }
Derek Lambertief7e6b62020-02-04 14:49:16 +0000177 };
Derek Lamberti836b27b2019-11-20 10:51:57 +0000178
Derek Lamberti5c510f82020-02-11 12:56:52 +0000179 TuningLevel tuningLevel = ConvertTuningLevel(clTunerParams->m_TuningLevel, clTunerParams->m_Mode);
180 ConfigureTuner(*tuner, tuningLevel);
Derek Lambertief7e6b62020-02-04 14:49:16 +0000181 }
182 }
183 else //New backend options API
184 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000185 const TuningLevel defaultTuningLevel = TuningLevel::None;
186 auto tuningLevel = defaultTuningLevel;
187
Derek Lambertief7e6b62020-02-04 14:49:16 +0000188 ParseOptions(options.m_BackendOptions, "GpuAcc", [&](std::string name, const BackendOptions::Var& value)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000189 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000190 if (name == "KernelProfilingEnabled")
191 {
192 kernelProfiling |= ParseBoolean(value, false);
193 } else if (name == "TuningFile")
194 {
195 m_TuningFile = ParseFile(value, "");
196 } else if (name == "TuningLevel")
197 {
198 tuningLevel = ParseTuningLevel(value, defaultTuningLevel);
199 }
200 });
Derek Lamberti836b27b2019-11-20 10:51:57 +0000201
Derek Lambertief7e6b62020-02-04 14:49:16 +0000202 // Create the tuner, in tuning mode initially.
203 m_Tuner = std::make_unique<arm_compute::CLTuner>(true);
204
Derek Lamberti5c510f82020-02-11 12:56:52 +0000205 ConfigureTuner(*(m_Tuner.get()), tuningLevel);
Derek Lambertief7e6b62020-02-04 14:49:16 +0000206
alered01a7227ac2020-05-07 14:58:29 +0100207 if (!m_TuningFile.empty() && tuningLevel == TuningLevel::None)
Derek Lambertief7e6b62020-02-04 14:49:16 +0000208 {
Derek Lamberti836b27b2019-11-20 10:51:57 +0000209 try
210 {
Jan Eilers2cd18472020-12-15 10:42:38 +0000211 ARMNN_LOG(info) << "Loading Gpu tuning data from file: " << m_TuningFile;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000212 m_Tuner->load_from_file(m_TuningFile.c_str());
alered01a7227ac2020-05-07 14:58:29 +0100213 }
214 catch (const std::exception& e)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000215 {
216 ARMNN_LOG(warning) << "Could not load GpuAcc tuner data file.";
217 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000218 }
alered01a7227ac2020-05-07 14:58:29 +0100219 tuner = m_Tuner.get();
Derek Lamberti836b27b2019-11-20 10:51:57 +0000220 }
221
222 m_ClContextControlWrapper = std::make_unique<ClContextControlWrapper>(
223 tuner,
224 kernelProfiling
225 );
David Beck1b61be52018-11-08 09:19:14 +0000226}
227
228bool ClBackendContext::BeforeLoadNetwork(NetworkId)
229{
230 return true;
231}
232
233bool ClBackendContext::AfterLoadNetwork(NetworkId networkId)
234{
235 {
236 std::lock_guard<std::mutex> lockGuard(m_Mutex);
237 m_NetworkIds.insert(networkId);
238 }
239 return true;
240}
241
242bool ClBackendContext::BeforeUnloadNetwork(NetworkId)
243{
244 return m_ClContextControlWrapper->Sync();
245}
246
247bool ClBackendContext::AfterUnloadNetwork(NetworkId networkId)
248{
249 bool clearCache = false;
250 {
251 std::lock_guard<std::mutex> lockGuard(m_Mutex);
252 m_NetworkIds.erase(networkId);
253 clearCache = m_NetworkIds.empty();
254 }
255
256 if (clearCache)
257 {
258 m_ClContextControlWrapper->ClearClCache();
259 }
260
261 return true;
262}
263
264ClBackendContext::~ClBackendContext()
265{
Derek Lamberti836b27b2019-11-20 10:51:57 +0000266 if (m_Tuner && !m_TuningFile.empty())
267 {
268 try
269 {
270 m_Tuner->save_to_file(m_TuningFile.c_str());
271 }
272 catch(const std::exception& e)
273 {
274 ARMNN_LOG(warning) << "Could not save GpuAcc tuner data to file " << m_TuningFile;
275 }
276 }
David Beck1b61be52018-11-08 09:19:14 +0000277}
278
279} // namespace armnn