ArmNN
 20.11
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  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.AsInt();
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  return defaultValue;
103 }
104 
105 std::string ParseFile(const BackendOptions::Var& value, std::string defaultValue)
106 {
107  if (value.IsString())
108  {
109  return value.AsString();
110  }
111  return defaultValue;
112 }
113 
114 void ConfigureTuner(arm_compute::CLTuner &tuner, TuningLevel level)
115 {
116  tuner.set_tune_new_kernels(true); // Turn on tuning initially.
117 
118  switch (level)
119  {
120  case TuningLevel::Rapid:
121  tuner.set_tuner_mode(arm_compute::CLTunerMode::RAPID);
122  break;
123  case TuningLevel::Normal:
124  tuner.set_tuner_mode(arm_compute::CLTunerMode::NORMAL);
125  break;
127  tuner.set_tuner_mode(arm_compute::CLTunerMode::EXHAUSTIVE);
128  break;
129  case TuningLevel::None:
130  default:
131  tuner.set_tune_new_kernels(false); // Turn off tuning. Set to "use" only mode.
132  break;
133  }
134 }
135 
137  : IBackendContext(options)
138  , m_TuningFile()
139 {
140  bool kernelProfiling = options.m_EnableGpuProfiling;
141 
142  arm_compute::CLTuner* tuner = nullptr;
143  bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
144  if (useLegacyTunerAPI)
145  {
146  auto clTunerParams = PolymorphicDowncast<ClTunedParameters*>(
147  options.m_GpuAccTunedParameters.get());
148  tuner = &clTunerParams->m_Tuner;
149 
150  if (tuner)
151  {
152  auto ConvertTuningLevel = [](IGpuAccTunedParameters::TuningLevel level,
154  {
156  {
157  return TuningLevel::None;
158  }
159 
160  switch(level)
161  {
163  return TuningLevel::Rapid;
165  return TuningLevel::Normal;
168  default:
169  {
170  ARMNN_ASSERT_MSG(false, "Tuning level not recognised.");
171  return TuningLevel::None;
172  }
173  }
174  };
175 
176  TuningLevel tuningLevel = ConvertTuningLevel(clTunerParams->m_TuningLevel, clTunerParams->m_Mode);
177  ConfigureTuner(*tuner, tuningLevel);
178  }
179  }
180  else //New backend options API
181  {
182  const TuningLevel defaultTuningLevel = TuningLevel::None;
183  auto tuningLevel = defaultTuningLevel;
184 
185  ParseOptions(options.m_BackendOptions, "GpuAcc", [&](std::string name, const BackendOptions::Var& value)
186  {
187  if (name == "KernelProfilingEnabled")
188  {
189  kernelProfiling |= ParseBoolean(value, false);
190  } else if (name == "TuningFile")
191  {
192  m_TuningFile = ParseFile(value, "");
193  } else if (name == "TuningLevel")
194  {
195  tuningLevel = ParseTuningLevel(value, defaultTuningLevel);
196  }
197  });
198 
199  // Create the tuner, in tuning mode initially.
200  m_Tuner = std::make_unique<arm_compute::CLTuner>(true);
201 
202  ConfigureTuner(*(m_Tuner.get()), tuningLevel);
203 
204  if (!m_TuningFile.empty() && tuningLevel == TuningLevel::None)
205  {
206  try
207  {
208  m_Tuner->load_from_file(m_TuningFile.c_str());
209  }
210  catch (const std::exception& e)
211  {
212  ARMNN_LOG(warning) << "Could not load GpuAcc tuner data file.";
213  }
214  }
215  tuner = m_Tuner.get();
216  }
217 
218  m_ClContextControlWrapper = std::make_unique<ClContextControlWrapper>(
219  tuner,
220  kernelProfiling
221  );
222 }
223 
225 {
226  return true;
227 }
228 
230 {
231  {
232  std::lock_guard<std::mutex> lockGuard(m_Mutex);
233  m_NetworkIds.insert(networkId);
234  }
235  return true;
236 }
237 
239 {
240  return m_ClContextControlWrapper->Sync();
241 }
242 
244 {
245  bool clearCache = false;
246  {
247  std::lock_guard<std::mutex> lockGuard(m_Mutex);
248  m_NetworkIds.erase(networkId);
249  clearCache = m_NetworkIds.empty();
250  }
251 
252  if (clearCache)
253  {
254  m_ClContextControlWrapper->ClearClCache();
255  }
256 
257  return true;
258 }
259 
261 {
262  if (m_Tuner && !m_TuningFile.empty())
263  {
264  try
265  {
266  m_Tuner->save_to_file(m_TuningFile.c_str());
267  }
268  catch(const std::exception& e)
269  {
270  ARMNN_LOG(warning) << "Could not save GpuAcc tuner data to file " << m_TuningFile;
271  }
272  }
273 }
274 
275 } // 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:20
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:52
std::vector< BackendOptions > m_BackendOptions
Pass backend specific options.
Definition: IRuntime.hpp:115
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
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:55
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)
bool BeforeUnloadNetwork(NetworkId networkId) override
Before and after Unload network events.