ArmNN
 22.08
ClBackendContext.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "ClBackendContext.hpp"
7 #include "ClContextControl.hpp"
8 
9 #include <armnn/Logging.hpp>
10 #include <armnn/utility/Assert.hpp>
12 
13 #include <arm_compute/core/CL/OpenCL.h>
14 #include <arm_compute/core/CL/CLKernelLibrary.h>
15 #include <arm_compute/runtime/CL/CLScheduler.h>
16 #include <arm_compute/runtime/CL/CLTunerTypes.h>
17 
18 namespace armnn
19 {
20 
21 struct ClBackendContext::ClContextControlWrapper
22 {
23  ClContextControlWrapper(arm_compute::CLTuner* tuner,
24  arm_compute::CLGEMMHeuristicsHandle* heuristicsHandle,
25  bool profilingEnabled)
26  : m_ClContextControl(tuner, heuristicsHandle, profilingEnabled)
27  {}
28 
29  bool Sync()
30  {
31  if (arm_compute::CLScheduler::get().context()() != NULL)
32  {
33  // Waits for all queued CL requests to finish before unloading the network they may be using.
34  try
35  {
36  // Coverity fix: arm_compute::CLScheduler::sync() may throw an exception of type cl::Error.
37  arm_compute::CLScheduler::get().sync();
38  }
39  catch (const cl::Error&)
40  {
41  ARMNN_LOG(warning) << "Runtime::UnloadNetwork(): an error occurred while waiting for "
42  "the queued CL requests to finish";
43  return false;
44  }
45  }
46 
47  return true;
48  }
49 
50  void ClearClCache()
51  {
52  if (arm_compute::CLScheduler::get().context()() != NULL)
53  {
54  // There are no loaded networks left, so clear the CL cache to free up memory
55  m_ClContextControl.ClearClCache();
56  }
57  }
58 
59  ClContextControl m_ClContextControl;
60 };
61 
62 std::string LowerString(std::string value)
63 {
64  std::transform(value.begin(), value.end(), value.begin(),
65  [](unsigned char c){ return std::tolower(c); });
66 
67  return value;
68 }
69 
70 enum class TuningLevel
71 {
72  None,
73  Rapid,
74  Normal,
76 };
77 
78 
80 {
81  if (value.IsInt())
82  {
83  int v = value.AsInt();
84  if (v > static_cast<int>(TuningLevel::Exhaustive) ||
85  v < static_cast<int>(TuningLevel::None))
86  {
87  ARMNN_LOG(warning) << "Invalid GpuAcc tuning level ("<< v << ") selected. "
88  "Using default(" << static_cast<int>(defaultValue) << ")";
89  } else
90  {
91  return static_cast<TuningLevel>(v);
92  }
93  }
94  return defaultValue;
95 }
96 
97 bool ParseBoolean(const BackendOptions::Var& value, bool defaultValue)
98 {
99  if (value.IsBool())
100  {
101  return value.AsBool();
102  }
103  return defaultValue;
104 }
105 
106 std::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 
115 void ConfigureTuner(arm_compute::CLTuner &tuner, TuningLevel level)
116 {
117  tuner.set_tune_new_kernels(true); // Turn on tuning initially.
118 
119  switch (level)
120  {
121  case TuningLevel::Rapid:
122  ARMNN_LOG(info) << "Gpu tuning is activated. TuningLevel: Rapid (1)";
123  tuner.set_tuner_mode(arm_compute::CLTunerMode::RAPID);
124  break;
125  case TuningLevel::Normal:
126  ARMNN_LOG(info) << "Gpu tuning is activated. TuningLevel: Normal (2)";
127  tuner.set_tuner_mode(arm_compute::CLTunerMode::NORMAL);
128  break;
130  ARMNN_LOG(info) << "Gpu tuning is activated. TuningLevel: Exhaustive (3)";
131  tuner.set_tuner_mode(arm_compute::CLTunerMode::EXHAUSTIVE);
132  break;
133  case TuningLevel::None:
134  default:
135  tuner.set_tune_new_kernels(false); // Turn off tuning. Set to "use" only mode.
136  break;
137  }
138 }
139 
141  : IBackendContext(options)
142  , m_TuningFile()
143 {
144  bool kernelProfiling = options.m_EnableGpuProfiling;
145 
146  arm_compute::CLTuner* tuner = nullptr;
147  arm_compute::CLGEMMHeuristicsHandle* mlgoTuner = nullptr;
148  bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
149  if (useLegacyTunerAPI)
150  {
151  auto clTunerParams = PolymorphicDowncast<ClTunedParameters*>(
152  options.m_GpuAccTunedParameters.get());
153  tuner = &clTunerParams->m_Tuner;
154 
155  if (tuner)
156  {
157  auto ConvertTuningLevel = [](IGpuAccTunedParameters::TuningLevel level,
159  {
161  {
162  return TuningLevel::None;
163  }
164 
165  switch(level)
166  {
168  return TuningLevel::Rapid;
170  return TuningLevel::Normal;
173  default:
174  {
175  ARMNN_ASSERT_MSG(false, "Tuning level not recognised.");
176  return TuningLevel::None;
177  }
178  }
179  };
180 
181  TuningLevel tuningLevel = ConvertTuningLevel(clTunerParams->m_TuningLevel, clTunerParams->m_Mode);
182  ConfigureTuner(*tuner, tuningLevel);
183  }
184  }
185  else //New backend options API
186  {
187  const TuningLevel defaultTuningLevel = TuningLevel::None;
188  auto tuningLevel = defaultTuningLevel;
189 
190  ParseOptions(options.m_BackendOptions, "GpuAcc", [&](std::string name, const BackendOptions::Var& value)
191  {
192  if (name == "KernelProfilingEnabled")
193  {
194  kernelProfiling |= ParseBoolean(value, false);
195  } else if (name == "TuningFile")
196  {
197  m_TuningFile = ParseFile(value, "");
198  } else if (name == "TuningLevel")
199  {
200  tuningLevel = ParseTuningLevel(value, defaultTuningLevel);
201  }
202  else if (name == "MLGOTuningFilePath")
203  {
204  m_MLGOTuningFile = ParseFile(value, "");
205  }
206  });
207 
208  // Create the tuner, in tuning mode initially.
209  m_Tuner = std::make_unique<arm_compute::CLTuner>(true);
210 
211  ConfigureTuner(*(m_Tuner.get()), tuningLevel);
212 
213  if (!m_TuningFile.empty())
214  {
215  try
216  {
217  ARMNN_LOG(info) << "Loading Gpu tuning data from file: " << m_TuningFile;
218  m_Tuner->load_from_file(m_TuningFile.c_str());
219  }
220  catch (const std::exception& e)
221  {
222  // Warn if not tuning, otherwise tuning will generate new params
223  if (tuningLevel == TuningLevel::None)
224  {
225  ARMNN_LOG(warning) << "Could not load GpuAcc tuner data file.";
226  }
227  }
228  }
229 
230  if (!m_MLGOTuningFile.empty())
231  {
232  try
233  {
234  ARMNN_LOG(info) << "Loading Gpu MLGO tuning data from file: " << m_TuningFile;
235  if(m_MLGOTuner.reload_from_file(m_MLGOTuningFile.c_str()))
236  {
237  mlgoTuner = &m_MLGOTuner;
238  }
239  }
240  catch (const std::exception& e)
241  {
242  ARMNN_LOG(warning) << "Could not load GpuAcc MLGO tuner data file.";
243  }
244  }
245 
246  tuner = m_Tuner.get();
247  }
248 
249  m_ClContextControlWrapper = std::make_unique<ClContextControlWrapper>(
250  tuner,
251  mlgoTuner,
252  kernelProfiling
253  );
254 }
255 
257 {
258  return true;
259 }
260 
262 {
263  {
264  std::lock_guard<std::mutex> lockGuard(m_Mutex);
265  m_NetworkIds.insert(networkId);
266  }
267  return true;
268 }
269 
271 {
272  return m_ClContextControlWrapper->Sync();
273 }
274 
276 {
277  bool clearCache = false;
278  {
279  std::lock_guard<std::mutex> lockGuard(m_Mutex);
280  m_NetworkIds.erase(networkId);
281  clearCache = m_NetworkIds.empty();
282  }
283 
284  if (clearCache)
285  {
286  m_ClContextControlWrapper->ClearClCache();
287  }
288 
289  return true;
290 }
291 
293 {
294  return m_ClContextControlWrapper->Sync();
295 }
296 
298 {
299  if (m_Tuner && !m_TuningFile.empty())
300  {
301  try
302  {
303  m_Tuner->save_to_file(m_TuningFile.c_str());
304  }
305  catch(const std::exception& e)
306  {
307  ARMNN_LOG(warning) << "Could not save GpuAcc tuner data to file " << m_TuningFile;
308  }
309  }
310 }
311 
312 } // namespace armnn
Very basic type safe variant.
bool BeforeLoadNetwork(NetworkId networkId) override
Before and after Load network events.
void ParseOptions(const std::vector< BackendOptions > &options, BackendId backend, F f)
bool AfterUnloadNetwork(NetworkId networkId) override
#define ARMNN_LOG(severity)
Definition: Logging.hpp:205
Copyright (c) 2021 ARM Limited and Contributors.
void ConfigureTuner(arm_compute::CLTuner &tuner, TuningLevel level)
ClBackendContext(const IRuntime::CreationOptions &options)
std::shared_ptr< IGpuAccTunedParameters > m_GpuAccTunedParameters
If set, uses the GpuAcc tuned parameters from the given object when executing GPU workloads...
Definition: IRuntime.hpp:90
std::vector< BackendOptions > m_BackendOptions
Pass backend specific options.
Definition: IRuntime.hpp:189
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
int NetworkId
Definition: IRuntime.hpp:27
bool AfterEnqueueWorkload(NetworkId networkId) override
std::string AsString() const
bool ParseBoolean(const BackendOptions::Var &value, bool defaultValue)
bool m_EnableGpuProfiling
Setting this flag will allow the user to obtain GPU profiling information from the runtime...
Definition: IRuntime.hpp:93
bool AsBool() const
Value getters.
std::string ParseFile(const BackendOptions::Var &value, std::string defaultValue)
TuningLevel ParseTuningLevel(const BackendOptions::Var &value, TuningLevel defaultValue)
bool IsBool() const
Type getters.
arm_compute::CLGEMMHeuristicsHandle m_MLGOTuner
bool AfterLoadNetwork(NetworkId networkId) override
std::string LowerString(std::string value)
bool BeforeUnloadNetwork(NetworkId networkId) override
Before and after Unload network events.