blob: bf5614588515f7ab20368025b6f96ef1e0ca62c4 [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>
10
David Beck1b61be52018-11-08 09:19:14 +000011#include <arm_compute/core/CL/OpenCL.h>
12#include <arm_compute/core/CL/CLKernelLibrary.h>
13#include <arm_compute/runtime/CL/CLScheduler.h>
Derek Lamberti836b27b2019-11-20 10:51:57 +000014#include <arm_compute/runtime/CL/CLTunerTypes.h>
15
16#include <boost/polymorphic_cast.hpp>
Aron Virginas-Tard46e6472018-11-16 10:26:23 +000017
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 {
82 int v = value.IsInt();
83 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
131ClBackendContext::ClBackendContext(const IRuntime::CreationOptions& options)
132 : IBackendContext(options)
David Beck1b61be52018-11-08 09:19:14 +0000133{
Derek Lamberti836b27b2019-11-20 10:51:57 +0000134 bool kernelProfiling = options.m_EnableGpuProfiling;
135 const TuningLevel defaultTuningLevel = TuningLevel::None;
136 auto tuningLevel = defaultTuningLevel;
137 m_TuningFile = "";
138
Derek Lamberti836b27b2019-11-20 10:51:57 +0000139 arm_compute::CLTuner* tuner = nullptr;
Derek Lambertief7e6b62020-02-04 14:49:16 +0000140 bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
141 if (useLegacyTunerAPI)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000142 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000143 auto clTunerParams = boost::polymorphic_downcast<ClTunedParameters*>(
144 options.m_GpuAccTunedParameters.get());
145 auto clTuner = &clTunerParams->m_Tuner;
Derek Lamberti836b27b2019-11-20 10:51:57 +0000146
Derek Lambertief7e6b62020-02-04 14:49:16 +0000147 if (clTuner)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000148 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000149 auto ConvertTuningLevel = [](IGpuAccTunedParameters::TuningLevel level)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000150 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000151 switch(level)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000152 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000153 case IGpuAccTunedParameters::TuningLevel::Rapid:
154 return arm_compute::CLTunerMode::RAPID;
155 case IGpuAccTunedParameters::TuningLevel::Normal:
156 return arm_compute::CLTunerMode::NORMAL;
157 case IGpuAccTunedParameters::TuningLevel::Exhaustive:
158 return arm_compute::CLTunerMode::EXHAUSTIVE;
159 default:
160 {
161 BOOST_ASSERT_MSG(false, "Tuning level not recognised.");
162 return arm_compute::CLTunerMode::NORMAL;
163 }
Derek Lamberti836b27b2019-11-20 10:51:57 +0000164 }
Derek Lambertief7e6b62020-02-04 14:49:16 +0000165 };
Derek Lamberti836b27b2019-11-20 10:51:57 +0000166
Derek Lambertief7e6b62020-02-04 14:49:16 +0000167 clTuner->set_tuner_mode(ConvertTuningLevel(clTunerParams->m_TuningLevel));
168 clTuner->set_tune_new_kernels(
169 clTunerParams->m_Mode == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters);
170 }
171 }
172 else //New backend options API
173 {
174 ParseOptions(options.m_BackendOptions, "GpuAcc", [&](std::string name, const BackendOptions::Var& value)
Derek Lamberti836b27b2019-11-20 10:51:57 +0000175 {
Derek Lambertief7e6b62020-02-04 14:49:16 +0000176 if (name == "KernelProfilingEnabled")
177 {
178 kernelProfiling |= ParseBoolean(value, false);
179 } else if (name == "TuningFile")
180 {
181 m_TuningFile = ParseFile(value, "");
182 } else if (name == "TuningLevel")
183 {
184 tuningLevel = ParseTuningLevel(value, defaultTuningLevel);
185 }
186 });
Derek Lamberti836b27b2019-11-20 10:51:57 +0000187
Derek Lambertief7e6b62020-02-04 14:49:16 +0000188 // Create the tuner, in tuning mode initially.
189 m_Tuner = std::make_unique<arm_compute::CLTuner>(true);
190
191 switch (tuningLevel)
192 {
193 case TuningLevel::Rapid:
194 m_Tuner->set_tuner_mode(arm_compute::CLTunerMode::RAPID);
195 break;
196 case TuningLevel::Normal:
197 m_Tuner->set_tuner_mode(arm_compute::CLTunerMode::NORMAL);
198 break;
199 case TuningLevel::Exhaustive:
200 m_Tuner->set_tuner_mode(arm_compute::CLTunerMode::EXHAUSTIVE);
201 break;
202 case TuningLevel::None:
203 default:
204 m_Tuner->set_tune_new_kernels(false); // Turn of tuning. Set to "use" only mode.
205 break;
206 }
207
208 if (!m_TuningFile.empty())
209 {
Derek Lamberti836b27b2019-11-20 10:51:57 +0000210 try
211 {
212 m_Tuner->load_from_file(m_TuningFile.c_str());
213 } catch (const std::exception& e)
214 {
215 ARMNN_LOG(warning) << "Could not load GpuAcc tuner data file.";
216 }
217
218 tuner = m_Tuner.get();
219 }
220 }
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