blob: 42f42b302363add05365ed7672693e1af872589f [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 }
102
103 return defaultValue;
104}
105
106std::string ParseFile(const BackendOptions::Var& value, std::string defaultValue)
107{
108 if (value.IsString())
109 {
110 return value.AsString();
111 }
112 return defaultValue;
113}
114
115template <typename F>
116void ParseOptions(const std::vector<BackendOptions>& options, BackendId backend, F f)
117{
118 for (auto optionsGroup : options)
119 {
120 if (optionsGroup.GetBackendId() == backend)
121 {
122 for (size_t i=0; i < optionsGroup.GetOptionCount(); i++)
123 {
124 const BackendOptions::BackendOption option = optionsGroup.GetOption(i);
125 f(option.GetName(), option.GetValue());
126 }
127 }
128 }
129}
David Beck1b61be52018-11-08 09:19:14 +0000130
Derek Lamberti5c510f82020-02-11 12:56:52 +0000131void ConfigureTuner(arm_compute::CLTuner &tuner, TuningLevel level)
132{
133 tuner.set_tune_new_kernels(true); // Turn on tuning initially.
134
135 switch (level)
136 {
137 case TuningLevel::Rapid:
138 tuner.set_tuner_mode(arm_compute::CLTunerMode::RAPID);
139 break;
140 case TuningLevel::Normal:
141 tuner.set_tuner_mode(arm_compute::CLTunerMode::NORMAL);
142 break;
143 case TuningLevel::Exhaustive:
144 tuner.set_tuner_mode(arm_compute::CLTunerMode::EXHAUSTIVE);
145 break;
146 case TuningLevel::None:
147 default:
148 tuner.set_tune_new_kernels(false); // Turn off tuning. Set to "use" only mode.
149 break;
150 }
151}
152
David Beck1b61be52018-11-08 09:19:14 +0000153ClBackendContext::ClBackendContext(const IRuntime::CreationOptions& options)
154 : IBackendContext(options)
Derek Lamberti5c510f82020-02-11 12:56:52 +0000155 , m_TuningFile()
David Beck1b61be52018-11-08 09:19:14 +0000156{
Derek Lamberti836b27b2019-11-20 10:51:57 +0000157 bool kernelProfiling = options.m_EnableGpuProfiling;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000158
Derek Lamberti836b27b2019-11-20 10:51:57 +0000159 arm_compute::CLTuner* tuner = nullptr;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000160 bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
161 if (useLegacyTunerAPI)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000162 {
Jan Eilersbb446e52020-04-02 13:56:54 +0100163 auto clTunerParams = PolymorphicDowncast<ClTunedParameters*>(
Derek Lambertief7e6b62020-02-04 14:49:16 +0000164 options.m_GpuAccTunedParameters.get());
Derek Lamberti5c510f82020-02-11 12:56:52 +0000165 tuner = &clTunerParams->m_Tuner;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000166
Derek Lamberti5c510f82020-02-11 12:56:52 +0000167 if (tuner)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000168 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000169 auto ConvertTuningLevel = [](IGpuAccTunedParameters::TuningLevel level,
170 armnn::IGpuAccTunedParameters::Mode mode)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000171 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000172 if (mode == armnn::IGpuAccTunedParameters::Mode::UseTunedParameters)
173 {
174 return TuningLevel::None;
175 }
176
Derek Lambertief7e6b62020-02-04 14:49:16 +0000177 switch(level)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000178 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000179 case IGpuAccTunedParameters::TuningLevel::Rapid:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000180 return TuningLevel::Rapid;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000181 case IGpuAccTunedParameters::TuningLevel::Normal:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000182 return TuningLevel::Normal;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000183 case IGpuAccTunedParameters::TuningLevel::Exhaustive:
Derek Lamberti5c510f82020-02-11 12:56:52 +0000184 return TuningLevel::Exhaustive;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000185 default:
186 {
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100187 ARMNN_ASSERT_MSG(false, "Tuning level not recognised.");
Derek Lamberti5c510f82020-02-11 12:56:52 +0000188 return TuningLevel::None;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000189 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000190 }
Derek Lambertief7e6b62020-02-04 14:49:16 +0000191 };
Derek Lamberti836b27b2019-11-20 10:51:57 +0000192
Derek Lamberti5c510f82020-02-11 12:56:52 +0000193 TuningLevel tuningLevel = ConvertTuningLevel(clTunerParams->m_TuningLevel, clTunerParams->m_Mode);
194 ConfigureTuner(*tuner, tuningLevel);
Derek Lambertief7e6b62020-02-04 14:49:16 +0000195 }
196 }
197 else //New backend options API
198 {
Derek Lamberti5c510f82020-02-11 12:56:52 +0000199 const TuningLevel defaultTuningLevel = TuningLevel::None;
200 auto tuningLevel = defaultTuningLevel;
201
Derek Lambertief7e6b62020-02-04 14:49:16 +0000202 ParseOptions(options.m_BackendOptions, "GpuAcc", [&](std::string name, const BackendOptions::Var& value)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000203 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000204 if (name == "KernelProfilingEnabled")
205 {
206 kernelProfiling |= ParseBoolean(value, false);
207 } else if (name == "TuningFile")
208 {
209 m_TuningFile = ParseFile(value, "");
210 } else if (name == "TuningLevel")
211 {
212 tuningLevel = ParseTuningLevel(value, defaultTuningLevel);
213 }
214 });
Derek Lamberti836b27b2019-11-20 10:51:57 +0000215
Derek Lambertief7e6b62020-02-04 14:49:16 +0000216 // Create the tuner, in tuning mode initially.
217 m_Tuner = std::make_unique<arm_compute::CLTuner>(true);
218
Derek Lamberti5c510f82020-02-11 12:56:52 +0000219 ConfigureTuner(*(m_Tuner.get()), tuningLevel);
Derek Lambertief7e6b62020-02-04 14:49:16 +0000220
alered01a7227ac2020-05-07 14:58:29 +0100221 if (!m_TuningFile.empty() && tuningLevel == TuningLevel::None)
Derek Lambertief7e6b62020-02-04 14:49:16 +0000222 {
Derek Lamberti836b27b2019-11-20 10:51:57 +0000223 try
224 {
225 m_Tuner->load_from_file(m_TuningFile.c_str());
alered01a7227ac2020-05-07 14:58:29 +0100226 }
227 catch (const std::exception& e)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000228 {
229 ARMNN_LOG(warning) << "Could not load GpuAcc tuner data file.";
230 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000231 }
alered01a7227ac2020-05-07 14:58:29 +0100232 tuner = m_Tuner.get();
Derek Lamberti836b27b2019-11-20 10:51:57 +0000233 }
234
235 m_ClContextControlWrapper = std::make_unique<ClContextControlWrapper>(
236 tuner,
237 kernelProfiling
238 );
David Beck1b61be52018-11-08 09:19:14 +0000239}
240
241bool ClBackendContext::BeforeLoadNetwork(NetworkId)
242{
243 return true;
244}
245
246bool ClBackendContext::AfterLoadNetwork(NetworkId networkId)
247{
248 {
249 std::lock_guard<std::mutex> lockGuard(m_Mutex);
250 m_NetworkIds.insert(networkId);
251 }
252 return true;
253}
254
255bool ClBackendContext::BeforeUnloadNetwork(NetworkId)
256{
257 return m_ClContextControlWrapper->Sync();
258}
259
260bool ClBackendContext::AfterUnloadNetwork(NetworkId networkId)
261{
262 bool clearCache = false;
263 {
264 std::lock_guard<std::mutex> lockGuard(m_Mutex);
265 m_NetworkIds.erase(networkId);
266 clearCache = m_NetworkIds.empty();
267 }
268
269 if (clearCache)
270 {
271 m_ClContextControlWrapper->ClearClCache();
272 }
273
274 return true;
275}
276
277ClBackendContext::~ClBackendContext()
278{
Derek Lamberti836b27b2019-11-20 10:51:57 +0000279 if (m_Tuner && !m_TuningFile.empty())
280 {
281 try
282 {
283 m_Tuner->save_to_file(m_TuningFile.c_str());
284 }
285 catch(const std::exception& e)
286 {
287 ARMNN_LOG(warning) << "Could not save GpuAcc tuner data to file " << m_TuningFile;
288 }
289 }
David Beck1b61be52018-11-08 09:19:14 +0000290}
291
292} // namespace armnn