blob: 22a4ceabd3ee63d55977ef76eb58777703cfafd8 [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:
121 tuner.set_tuner_mode(arm_compute::CLTunerMode::RAPID);
122 break;
123 case TuningLevel::Normal:
124 tuner.set_tuner_mode(arm_compute::CLTunerMode::NORMAL);
125 break;
126 case TuningLevel::Exhaustive:
127 tuner.set_tuner_mode(arm_compute::CLTunerMode::EXHAUSTIVE);
128 break;
129 case TuningLevel::None:
130 default:
131 tuner.set_tune_new_kernels(false); // Turn off tuning. Set to "use" only mode.
132 break;
133 }
134}
135
David Beck1b61be52018-11-08 09:19:14 +0000136ClBackendContext::ClBackendContext(const IRuntime::CreationOptions& options)
137 : IBackendContext(options)
Derek Lamberti5c510f82020-02-11 12:56:52 +0000138 , m_TuningFile()
David Beck1b61be52018-11-08 09:19:14 +0000139{
Derek Lamberti836b27b2019-11-20 10:51:57 +0000140 bool kernelProfiling = options.m_EnableGpuProfiling;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000141
Derek Lamberti836b27b2019-11-20 10:51:57 +0000142 arm_compute::CLTuner* tuner = nullptr;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000143 bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
144 if (useLegacyTunerAPI)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000145 {
Jan Eilersbb446e52020-04-02 13:56:54 +0100146 auto clTunerParams = PolymorphicDowncast<ClTunedParameters*>(
Derek Lambertief7e6b62020-02-04 14:49:16 +0000147 options.m_GpuAccTunedParameters.get());
Derek Lamberti5c510f82020-02-11 12:56:52 +0000148 tuner = &clTunerParams->m_Tuner;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000149
Derek Lamberti5c510f82020-02-11 12:56:52 +0000150 if (tuner)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000151 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000152 auto ConvertTuningLevel = [](IGpuAccTunedParameters::TuningLevel level,
153 armnn::IGpuAccTunedParameters::Mode mode)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000154 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000155 if (mode == armnn::IGpuAccTunedParameters::Mode::UseTunedParameters)
156 {
157 return TuningLevel::None;
158 }
159
Derek Lambertief7e6b62020-02-04 14:49:16 +0000160 switch(level)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000161 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000162 case IGpuAccTunedParameters::TuningLevel::Rapid:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000163 return TuningLevel::Rapid;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000164 case IGpuAccTunedParameters::TuningLevel::Normal:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000165 return TuningLevel::Normal;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000166 case IGpuAccTunedParameters::TuningLevel::Exhaustive:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000167 return TuningLevel::Exhaustive;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000168 default:
169 {
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100170 ARMNN_ASSERT_MSG(false, "Tuning level not recognised.");
Derek Lamberti5c510f82020-02-11 12:56:52 +0000171 return TuningLevel::None;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000172 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000173 }
Derek Lambertief7e6b62020-02-04 14:49:16 +0000174 };
Derek Lamberti836b27b2019-11-20 10:51:57 +0000175
Derek Lamberti5c510f82020-02-11 12:56:52 +0000176 TuningLevel tuningLevel = ConvertTuningLevel(clTunerParams->m_TuningLevel, clTunerParams->m_Mode);
177 ConfigureTuner(*tuner, tuningLevel);
Derek Lambertief7e6b62020-02-04 14:49:16 +0000178 }
179 }
180 else //New backend options API
181 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000182 const TuningLevel defaultTuningLevel = TuningLevel::None;
183 auto tuningLevel = defaultTuningLevel;
184
Derek Lambertief7e6b62020-02-04 14:49:16 +0000185 ParseOptions(options.m_BackendOptions, "GpuAcc", [&](std::string name, const BackendOptions::Var& value)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000186 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000187 if (name == "KernelProfilingEnabled")
188 {
189 kernelProfiling |= ParseBoolean(value, false);
190 } else if (name == "TuningFile")
191 {
192 m_TuningFile = ParseFile(value, "");
193 } else if (name == "TuningLevel")
194 {
195 tuningLevel = ParseTuningLevel(value, defaultTuningLevel);
196 }
197 });
Derek Lamberti836b27b2019-11-20 10:51:57 +0000198
Derek Lambertief7e6b62020-02-04 14:49:16 +0000199 // Create the tuner, in tuning mode initially.
200 m_Tuner = std::make_unique<arm_compute::CLTuner>(true);
201
Derek Lamberti5c510f82020-02-11 12:56:52 +0000202 ConfigureTuner(*(m_Tuner.get()), tuningLevel);
Derek Lambertief7e6b62020-02-04 14:49:16 +0000203
alered01a7227ac2020-05-07 14:58:29 +0100204 if (!m_TuningFile.empty() && tuningLevel == TuningLevel::None)
Derek Lambertief7e6b62020-02-04 14:49:16 +0000205 {
Derek Lamberti836b27b2019-11-20 10:51:57 +0000206 try
207 {
208 m_Tuner->load_from_file(m_TuningFile.c_str());
alered01a7227ac2020-05-07 14:58:29 +0100209 }
210 catch (const std::exception& e)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000211 {
212 ARMNN_LOG(warning) << "Could not load GpuAcc tuner data file.";
213 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000214 }
alered01a7227ac2020-05-07 14:58:29 +0100215 tuner = m_Tuner.get();
Derek Lamberti836b27b2019-11-20 10:51:57 +0000216 }
217
218 m_ClContextControlWrapper = std::make_unique<ClContextControlWrapper>(
219 tuner,
220 kernelProfiling
221 );
David Beck1b61be52018-11-08 09:19:14 +0000222}
223
224bool ClBackendContext::BeforeLoadNetwork(NetworkId)
225{
226 return true;
227}
228
229bool ClBackendContext::AfterLoadNetwork(NetworkId networkId)
230{
231 {
232 std::lock_guard<std::mutex> lockGuard(m_Mutex);
233 m_NetworkIds.insert(networkId);
234 }
235 return true;
236}
237
238bool ClBackendContext::BeforeUnloadNetwork(NetworkId)
239{
240 return m_ClContextControlWrapper->Sync();
241}
242
243bool ClBackendContext::AfterUnloadNetwork(NetworkId networkId)
244{
245 bool clearCache = false;
246 {
247 std::lock_guard<std::mutex> lockGuard(m_Mutex);
248 m_NetworkIds.erase(networkId);
249 clearCache = m_NetworkIds.empty();
250 }
251
252 if (clearCache)
253 {
254 m_ClContextControlWrapper->ClearClCache();
255 }
256
257 return true;
258}
259
260ClBackendContext::~ClBackendContext()
261{
Derek Lamberti836b27b2019-11-20 10:51:57 +0000262 if (m_Tuner && !m_TuningFile.empty())
263 {
264 try
265 {
266 m_Tuner->save_to_file(m_TuningFile.c_str());
267 }
268 catch(const std::exception& e)
269 {
270 ARMNN_LOG(warning) << "Could not save GpuAcc tuner data to file " << m_TuningFile;
271 }
272 }
David Beck1b61be52018-11-08 09:19:14 +0000273}
274
275} // namespace armnn