ArmNN
 20.02
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 
11 #include <arm_compute/core/CL/OpenCL.h>
12 #include <arm_compute/core/CL/CLKernelLibrary.h>
13 #include <arm_compute/runtime/CL/CLScheduler.h>
14 #include <arm_compute/runtime/CL/CLTunerTypes.h>
15 
16 #include <boost/polymorphic_cast.hpp>
17 
18 namespace armnn
19 {
20 
21 struct ClBackendContext::ClContextControlWrapper
22 {
23  ClContextControlWrapper(arm_compute::CLTuner* tuner,
24  bool profilingEnabled)
25  : m_ClContextControl(tuner, profilingEnabled)
26  {}
27 
28  bool Sync()
29  {
30  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  {
40  ARMNN_LOG(warning) << "Runtime::UnloadNetwork(): an error occurred while waiting for "
41  "the queued CL requests to finish";
42  return false;
43  }
44  }
45 
46  return true;
47  }
48 
49  void ClearClCache()
50  {
51  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  }
56  }
57 
58  ClContextControl m_ClContextControl;
59 };
60 
61 std::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 
69 enum class TuningLevel
70 {
71  None,
72  Rapid,
73  Normal,
75 };
76 
77 
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 
96 bool ParseBoolean(const BackendOptions::Var& value, bool defaultValue)
97 {
98  if (value.IsBool())
99  {
100  return value.AsBool();
101  }
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 template <typename F>
116 void 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 }
130 
131 void 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;
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 
154  : IBackendContext(options)
155  , m_TuningFile()
156 {
157  bool kernelProfiling = options.m_EnableGpuProfiling;
158 
159  arm_compute::CLTuner* tuner = nullptr;
160  bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
161  if (useLegacyTunerAPI)
162  {
163  auto clTunerParams = boost::polymorphic_downcast<ClTunedParameters*>(
164  options.m_GpuAccTunedParameters.get());
165  tuner = &clTunerParams->m_Tuner;
166 
167  if (tuner)
168  {
169  auto ConvertTuningLevel = [](IGpuAccTunedParameters::TuningLevel level,
171  {
173  {
174  return TuningLevel::None;
175  }
176 
177  switch(level)
178  {
180  return TuningLevel::Rapid;
182  return TuningLevel::Normal;
185  default:
186  {
187  BOOST_ASSERT_MSG(false, "Tuning level not recognised.");
188  return TuningLevel::None;
189  }
190  }
191  };
192 
193  TuningLevel tuningLevel = ConvertTuningLevel(clTunerParams->m_TuningLevel, clTunerParams->m_Mode);
194  ConfigureTuner(*tuner, tuningLevel);
195  }
196  }
197  else //New backend options API
198  {
199  const TuningLevel defaultTuningLevel = TuningLevel::None;
200  auto tuningLevel = defaultTuningLevel;
201 
202  ParseOptions(options.m_BackendOptions, "GpuAcc", [&](std::string name, const BackendOptions::Var& value)
203  {
204  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  });
215 
216  // Create the tuner, in tuning mode initially.
217  m_Tuner = std::make_unique<arm_compute::CLTuner>(true);
218 
219  ConfigureTuner(*(m_Tuner.get()), tuningLevel);
220 
221  if (!m_TuningFile.empty())
222  {
223  try
224  {
225  m_Tuner->load_from_file(m_TuningFile.c_str());
226  } catch (const std::exception& e)
227  {
228  ARMNN_LOG(warning) << "Could not load GpuAcc tuner data file.";
229  }
230 
231  tuner = m_Tuner.get();
232  }
233  }
234 
235  m_ClContextControlWrapper = std::make_unique<ClContextControlWrapper>(
236  tuner,
237  kernelProfiling
238  );
239 }
240 
242 {
243  return true;
244 }
245 
247 {
248  {
249  std::lock_guard<std::mutex> lockGuard(m_Mutex);
250  m_NetworkIds.insert(networkId);
251  }
252  return true;
253 }
254 
256 {
257  return m_ClContextControlWrapper->Sync();
258 }
259 
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 
278 {
279  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  }
290 }
291 
292 } // 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:163
int NetworkId
Definition: IRuntime.hpp:19
Copyright (c) 2020 ARM Limited.
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:51
std::vector< BackendOptions > m_BackendOptions
Pass backend specific options.
Definition: IRuntime.hpp:108
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:54
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.
bool AfterLoadNetwork(NetworkId networkId) override
std::string LowerString(std::string value)
armnn::Runtime::CreationOptions::ExternalProfilingOptions options
bool BeforeUnloadNetwork(NetworkId networkId) override
Before and after Unload network events.