• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2017, 2023 Arm Ltd and Contributors. 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>
11 #include <armnn/utility/PolymorphicDowncast.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 {
ClContextControlWrapperarmnn::ClBackendContext::ClContextControlWrapper23     ClContextControlWrapper(arm_compute::CLTuner* tuner,
24                             arm_compute::CLGEMMHeuristicsHandle* heuristicsHandle,
25                             bool profilingEnabled)
26         : m_ClContextControl(tuner, heuristicsHandle, profilingEnabled)
27     {}
28 
Syncarmnn::ClBackendContext::ClContextControlWrapper29     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 
ClearClCachearmnn::ClBackendContext::ClContextControlWrapper50     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 
ClBackendContext(const IRuntime::CreationOptions & options)62 ClBackendContext::ClBackendContext(const IRuntime::CreationOptions& options)
63     : IBackendContext(options)
64     , m_TuningFile()
65 {
66     bool kernelProfiling = options.m_EnableGpuProfiling;
67 
68     arm_compute::CLTuner* tuner = nullptr;
69     arm_compute::CLGEMMHeuristicsHandle* mlgoTuner = nullptr;
70     bool useLegacyTunerAPI = options.m_GpuAccTunedParameters.get() != nullptr;
71     if (useLegacyTunerAPI)
72     {
73         auto clTunerParams = PolymorphicDowncast<ClTunedParameters*>(
74                                 options.m_GpuAccTunedParameters.get());
75         tuner = &clTunerParams->m_Tuner;
76 
77         if (tuner)
78         {
79             auto ConvertTuningLevel = [](IGpuAccTunedParameters::TuningLevel level,
80                                          armnn::IGpuAccTunedParameters::Mode mode)
81                 {
82                     if (mode == armnn::IGpuAccTunedParameters::Mode::UseTunedParameters)
83                     {
84                         return TuningLevel::None;
85                     }
86 
87                     switch(level)
88                     {
89                         case IGpuAccTunedParameters::TuningLevel::Rapid:
90                             return TuningLevel::Rapid;
91                         case IGpuAccTunedParameters::TuningLevel::Normal:
92                             return TuningLevel::Normal;
93                         case IGpuAccTunedParameters::TuningLevel::Exhaustive:
94                             return TuningLevel::Exhaustive;
95                         default:
96                         {
97                             ARMNN_ASSERT_MSG(false, "Tuning level not recognised.");
98                             return TuningLevel::None;
99                         }
100                     }
101                 };
102 
103             TuningLevel tuningLevel = ConvertTuningLevel(clTunerParams->m_TuningLevel, clTunerParams->m_Mode);
104             ConfigureTuner(*tuner, tuningLevel);
105         }
106     }
107     else //New backend options API
108     {
109         const TuningLevel defaultTuningLevel = TuningLevel::None;
110         auto tuningLevel = defaultTuningLevel;
111 
112         ParseOptions(options.m_BackendOptions, "GpuAcc", [&](std::string name, const BackendOptions::Var& value)
113             {
114                 if (name == "KernelProfilingEnabled")
115                 {
116                     kernelProfiling |= ParseBooleanBackendOption(value, false);
117                 } else if (name == "TuningFile")
118                 {
119                     m_TuningFile = ParseStringBackendOption(value, "");
120                 } else if (name == "TuningLevel")
121                 {
122                     tuningLevel = ParseTuningLevel(value, defaultTuningLevel);
123                 }
124                 else if (name == "MLGOTuningFilePath")
125                 {
126                     m_MLGOTuningFile = ParseStringBackendOption(value, "");
127                 }
128             });
129 
130         // Create the tuner, in tuning mode initially.
131         m_Tuner = std::make_unique<arm_compute::CLTuner>(true);
132 
133         ConfigureTuner(*(m_Tuner.get()), tuningLevel);
134 
135         if (!m_TuningFile.empty())
136         {
137             try
138             {
139                 ARMNN_LOG(info) << "Loading Gpu tuning data from file: " << m_TuningFile;
140                 m_Tuner->load_from_file(m_TuningFile.c_str());
141             }
142             catch (const std::exception& e)
143             {
144                 // Warn if not tuning, otherwise tuning will generate new params
145                 if (tuningLevel == TuningLevel::None)
146                 {
147                     ARMNN_LOG(warning) << "Could not load GpuAcc tuner data file.";
148                 }
149             }
150         }
151 
152         if (!m_MLGOTuningFile.empty())
153         {
154             try
155             {
156                 ARMNN_LOG(info) << "Loading Gpu MLGO tuning data from file: " << m_TuningFile;
157                 if(m_MLGOTuner.reload_from_file(m_MLGOTuningFile.c_str()))
158                 {
159                     mlgoTuner = &m_MLGOTuner;
160                 }
161             }
162             catch (const std::exception& e)
163             {
164                 ARMNN_LOG(warning) << "Could not load GpuAcc MLGO tuner data file.";
165             }
166         }
167 
168         tuner = m_Tuner.get();
169     }
170 
171     m_ClContextControlWrapper = std::make_unique<ClContextControlWrapper>(
172             tuner,
173             mlgoTuner,
174             kernelProfiling
175     );
176 }
177 
BeforeLoadNetwork(NetworkId)178 bool ClBackendContext::BeforeLoadNetwork(NetworkId)
179 {
180     return true;
181 }
182 
AfterLoadNetwork(NetworkId networkId)183 bool ClBackendContext::AfterLoadNetwork(NetworkId networkId)
184 {
185     {
186         std::lock_guard<std::mutex> lockGuard(m_Mutex);
187         m_NetworkIds.insert(networkId);
188     }
189     return true;
190 }
191 
BeforeUnloadNetwork(NetworkId)192 bool ClBackendContext::BeforeUnloadNetwork(NetworkId)
193 {
194     return m_ClContextControlWrapper->Sync();
195 }
196 
AfterUnloadNetwork(NetworkId networkId)197 bool ClBackendContext::AfterUnloadNetwork(NetworkId networkId)
198 {
199     bool clearCache = false;
200     {
201         std::lock_guard<std::mutex> lockGuard(m_Mutex);
202         m_NetworkIds.erase(networkId);
203         clearCache = m_NetworkIds.empty();
204     }
205 
206     if (clearCache)
207     {
208         m_ClContextControlWrapper->ClearClCache();
209     }
210 
211     return true;
212 }
213 
AfterEnqueueWorkload(NetworkId)214 bool ClBackendContext::AfterEnqueueWorkload(NetworkId)
215 {
216     return m_ClContextControlWrapper->Sync();
217 }
218 
~ClBackendContext()219 ClBackendContext::~ClBackendContext()
220 {
221     if (m_Tuner && !m_TuningFile.empty())
222     {
223         try
224         {
225             m_Tuner->save_to_file(m_TuningFile.c_str());
226         }
227         catch(const std::exception& e)
228         {
229             ARMNN_LOG(warning) << "Could not save GpuAcc tuner data to file " << m_TuningFile;
230         }
231     }
232 }
233 
234 } // namespace armnn