blob: b435c2932393811fcf3529d76121c0d361fe3b36 [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
139
140 arm_compute::CLTuner* tuner = nullptr;
141 if (m_TuningFile.empty() == false)
142 {
143 bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
144 if (useLegacyTunerAPI)
145 {
146 auto clTunerParams = boost::polymorphic_downcast<ClTunedParameters*>(
147 options.m_GpuAccTunedParameters.get());
148 auto clTuner = &clTunerParams->m_Tuner;
149
150 if (clTuner)
151 {
152 auto ConvertTuningLevel = [](IGpuAccTunedParameters::TuningLevel level)
153 {
154 switch(level)
155 {
156 case IGpuAccTunedParameters::TuningLevel::Rapid:
157 return arm_compute::CLTunerMode::RAPID;
158 case IGpuAccTunedParameters::TuningLevel::Normal:
159 return arm_compute::CLTunerMode::NORMAL;
160 case IGpuAccTunedParameters::TuningLevel::Exhaustive:
161 return arm_compute::CLTunerMode::EXHAUSTIVE;
162 default:
163 {
164 BOOST_ASSERT_MSG(false, "Tuning level not recognised.");
165 return arm_compute::CLTunerMode::NORMAL;
166 }
167 }
168 };
169
170 clTuner->set_tuner_mode(ConvertTuningLevel(clTunerParams->m_TuningLevel));
171 clTuner->set_tune_new_kernels(
172 clTunerParams->m_Mode == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters);
173 }
174 }
175 else //New backend options API
176 {
177 ParseOptions(options.m_BackendOptions, "GpuAcc", [&](std::string name, const BackendOptions::Var& value)
178 {
179 if (name == "KernelProfilingEnabled")
180 {
181 kernelProfiling |= ParseBoolean(value, false);
182 } else if (name == "TuningFile")
183 {
184 m_TuningFile = ParseFile(value, "");
185 } else if (name == "TuningLevel")
186 {
187 tuningLevel = ParseTuningLevel(value, defaultTuningLevel);
188 }
189 });
190
191 // Create the tuner, in tuning mode initially.
192 m_Tuner = std::make_unique<arm_compute::CLTuner>(true);
193
194 switch (tuningLevel)
195 {
196 case TuningLevel::Rapid:
197 m_Tuner->set_tuner_mode(arm_compute::CLTunerMode::RAPID);
198 break;
199 case TuningLevel::Normal:
200 m_Tuner->set_tuner_mode(arm_compute::CLTunerMode::NORMAL);
201 break;
202 case TuningLevel::Exhaustive:
203 m_Tuner->set_tuner_mode(arm_compute::CLTunerMode::EXHAUSTIVE);
204 break;
205 case TuningLevel::None:
206 default:
207 m_Tuner->set_tune_new_kernels(false); // Turn of tuning. Set to "use" only mode.
208 break;
209 }
210
211 try
212 {
213 m_Tuner->load_from_file(m_TuningFile.c_str());
214 } catch (const std::exception& e)
215 {
216 ARMNN_LOG(warning) << "Could not load GpuAcc tuner data file.";
217 }
218
219 tuner = m_Tuner.get();
220 }
221 }
222
223 m_ClContextControlWrapper = std::make_unique<ClContextControlWrapper>(
224 tuner,
225 kernelProfiling
226 );
David Beck1b61be52018-11-08 09:19:14 +0000227}
228
229bool ClBackendContext::BeforeLoadNetwork(NetworkId)
230{
231 return true;
232}
233
234bool ClBackendContext::AfterLoadNetwork(NetworkId networkId)
235{
236 {
237 std::lock_guard<std::mutex> lockGuard(m_Mutex);
238 m_NetworkIds.insert(networkId);
239 }
240 return true;
241}
242
243bool ClBackendContext::BeforeUnloadNetwork(NetworkId)
244{
245 return m_ClContextControlWrapper->Sync();
246}
247
248bool ClBackendContext::AfterUnloadNetwork(NetworkId networkId)
249{
250 bool clearCache = false;
251 {
252 std::lock_guard<std::mutex> lockGuard(m_Mutex);
253 m_NetworkIds.erase(networkId);
254 clearCache = m_NetworkIds.empty();
255 }
256
257 if (clearCache)
258 {
259 m_ClContextControlWrapper->ClearClCache();
260 }
261
262 return true;
263}
264
265ClBackendContext::~ClBackendContext()
266{
Derek Lamberti836b27b2019-11-20 10:51:57 +0000267 if (m_Tuner && !m_TuningFile.empty())
268 {
269 try
270 {
271 m_Tuner->save_to_file(m_TuningFile.c_str());
272 }
273 catch(const std::exception& e)
274 {
275 ARMNN_LOG(warning) << "Could not save GpuAcc tuner data to file " << m_TuningFile;
276 }
277 }
David Beck1b61be52018-11-08 09:19:14 +0000278}
279
280} // namespace armnn