blob: f307133085a67b0bd99cba8c88ae7c7255a6ff05 [file] [log] [blame]
surmeh013537c2c2018-05-18 16:31:43 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
surmeh013537c2c2018-05-18 16:31:43 +01004//
5
6#include "ClContextControl.hpp"
7
Aron Virginas-Tar74ba3dc2018-11-15 17:44:36 +00008#include <armnn/Exceptions.hpp>
surmeh013537c2c2018-05-18 16:31:43 +01009
Aron Virginas-Tar74ba3dc2018-11-15 17:44:36 +000010#include <LeakChecking.hpp>
11
Jan Eilers8eb25602020-03-09 12:13:48 +000012#include <armnn/utility/IgnoreUnused.hpp>
13
surmeh013537c2c2018-05-18 16:31:43 +010014#include <arm_compute/core/CL/CLKernelLibrary.h>
15#include <arm_compute/runtime/CL/CLScheduler.h>
surmeh013537c2c2018-05-18 16:31:43 +010016
17#include <boost/assert.hpp>
18#include <boost/format.hpp>
surmeh013537c2c2018-05-18 16:31:43 +010019#include <boost/polymorphic_cast.hpp>
20
surmeh013537c2c2018-05-18 16:31:43 +010021namespace cl
22{
23class Context;
24class CommandQueue;
25class Device;
26}
27
28namespace armnn
29{
30
Derek Lamberti836b27b2019-11-20 10:51:57 +000031ClContextControl::ClContextControl(arm_compute::CLTuner *tuner,
telsoa01c577f2c2018-08-31 09:22:23 +010032 bool profilingEnabled)
Derek Lamberti836b27b2019-11-20 10:51:57 +000033 : m_Tuner(tuner)
telsoa01c577f2c2018-08-31 09:22:23 +010034 , m_ProfilingEnabled(profilingEnabled)
surmeh013537c2c2018-05-18 16:31:43 +010035{
telsoa01c577f2c2018-08-31 09:22:23 +010036 // Ignore m_ProfilingEnabled if unused to avoid compiling problems when ArmCompute is disabled.
Jan Eilers8eb25602020-03-09 12:13:48 +000037 IgnoreUnused(m_ProfilingEnabled);
telsoa01c577f2c2018-08-31 09:22:23 +010038
surmeh013537c2c2018-05-18 16:31:43 +010039 try
40 {
41 std::vector<cl::Platform> platforms;
42 cl::Platform::get(&platforms);
43
telsoa01c577f2c2018-08-31 09:22:23 +010044 // Selects default platform for the first element.
surmeh013537c2c2018-05-18 16:31:43 +010045 cl::Platform::setDefault(platforms[0]);
46
47 std::vector<cl::Device> devices;
48 platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
49
telsoa01c577f2c2018-08-31 09:22:23 +010050 // Selects default device for the first element.
surmeh013537c2c2018-05-18 16:31:43 +010051 cl::Device::setDefault(devices[0]);
52 }
53 catch (const cl::Error& clError)
54 {
55 throw ClRuntimeUnavailableException(boost::str(boost::format(
56 "Could not initialize the CL runtime. Error description: %1%. CL error code: %2%"
57 ) % clError.what() % clError.err()));
58 }
59
telsoa01c577f2c2018-08-31 09:22:23 +010060 // Removes the use of global CL context.
surmeh013537c2c2018-05-18 16:31:43 +010061 cl::Context::setDefault(cl::Context{});
62 BOOST_ASSERT(cl::Context::getDefault()() == NULL);
63
telsoa01c577f2c2018-08-31 09:22:23 +010064 // Removes the use of global CL command queue.
surmeh013537c2c2018-05-18 16:31:43 +010065 cl::CommandQueue::setDefault(cl::CommandQueue{});
66 BOOST_ASSERT(cl::CommandQueue::getDefault()() == NULL);
67
telsoa01c577f2c2018-08-31 09:22:23 +010068 // Always load the OpenCL runtime.
surmeh013537c2c2018-05-18 16:31:43 +010069 LoadOpenClRuntime();
surmeh013537c2c2018-05-18 16:31:43 +010070}
71
72ClContextControl::~ClContextControl()
73{
telsoa01c577f2c2018-08-31 09:22:23 +010074 // Load the OpencCL runtime without the tuned parameters to free the memory for them.
surmeh013537c2c2018-05-18 16:31:43 +010075 try
76 {
77 UnloadOpenClRuntime();
78 }
79 catch (const cl::Error& clError)
80 {
telsoa01c577f2c2018-08-31 09:22:23 +010081 // This should not happen, it is ignored if it does.
surmeh013537c2c2018-05-18 16:31:43 +010082
83 // Coverity fix: BOOST_LOG_TRIVIAL (previously used here to report the error) may throw an
84 // exception of type std::length_error.
85 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
86 std::cerr << "A CL error occurred unloading the runtime tuner parameters: "
87 << clError.what() << ". CL error code is: " << clError.err() << std::endl;
88 }
surmeh013537c2c2018-05-18 16:31:43 +010089}
90
91void ClContextControl::LoadOpenClRuntime()
92{
93 DoLoadOpenClRuntime(true);
94}
95
96void ClContextControl::UnloadOpenClRuntime()
97{
98 DoLoadOpenClRuntime(false);
99}
100
Derek Lamberti836b27b2019-11-20 10:51:57 +0000101void ClContextControl::DoLoadOpenClRuntime(bool updateTunedParameters)
surmeh013537c2c2018-05-18 16:31:43 +0100102{
surmeh013537c2c2018-05-18 16:31:43 +0100103 cl::Device device = cl::Device::getDefault();
104 cl::Context context;
105 cl::CommandQueue commandQueue;
106
James Conroy663c1842019-11-01 15:21:48 +0000107 if (arm_compute::CLScheduler::get().is_initialised() && arm_compute::CLScheduler::get().context()() != NULL)
surmeh013537c2c2018-05-18 16:31:43 +0100108 {
telsoa01c577f2c2018-08-31 09:22:23 +0100109 // Wait for all queued CL requests to finish before reinitialising it.
surmeh013537c2c2018-05-18 16:31:43 +0100110 arm_compute::CLScheduler::get().sync();
111 }
112
113 try
114 {
115 arm_compute::CLKernelLibrary::get().clear_programs_cache();
telsoa01c577f2c2018-08-31 09:22:23 +0100116 // Initialise the scheduler with a dummy context to release the LLVM data (which only happens when there are no
surmeh013537c2c2018-05-18 16:31:43 +0100117 // context references); it is initialised again, with a proper context, later.
118 arm_compute::CLScheduler::get().init(context, commandQueue, device);
119 arm_compute::CLKernelLibrary::get().init(".", context, device);
120
121 {
122 //
telsoa01c577f2c2018-08-31 09:22:23 +0100123 // Here we replace the context with a new one in which
124 // the memory leak checks show it as an extra allocation but
125 // because of the scope of the leak checks, it doesn't count
surmeh013537c2c2018-05-18 16:31:43 +0100126 // the disposal of the original object. On the other hand it
127 // does count the creation of this context which it flags
128 // as a memory leak. By adding the following line we prevent
129 // this to happen.
130 //
131 ARMNN_DISABLE_LEAK_CHECKING_IN_SCOPE();
132 context = cl::Context(device);
133 }
134
telsoa01c577f2c2018-08-31 09:22:23 +0100135 // NOTE: In this specific case profiling has to be enabled on the command queue
136 // in order for the CLTuner to work.
Derek Lamberti836b27b2019-11-20 10:51:57 +0000137 bool profilingNeededForClTuner = updateTunedParameters && m_Tuner &&
138 m_Tuner->tune_new_kernels();
surmeh013537c2c2018-05-18 16:31:43 +0100139
telsoa01c577f2c2018-08-31 09:22:23 +0100140 if (m_ProfilingEnabled || profilingNeededForClTuner)
surmeh013537c2c2018-05-18 16:31:43 +0100141 {
telsoa01c577f2c2018-08-31 09:22:23 +0100142 // Create a new queue with profiling enabled.
surmeh013537c2c2018-05-18 16:31:43 +0100143 commandQueue = cl::CommandQueue(context, device, CL_QUEUE_PROFILING_ENABLE);
144 }
145 else
146 {
telsoa01c577f2c2018-08-31 09:22:23 +0100147 // Use default queue.
surmeh013537c2c2018-05-18 16:31:43 +0100148 commandQueue = cl::CommandQueue(context, device);
149 }
150 }
151 catch (const cl::Error& clError)
152 {
153 throw ClRuntimeUnavailableException(boost::str(boost::format(
154 "Could not initialize the CL runtime. Error description: %1%. CL error code: %2%"
155 ) % clError.what() % clError.err()));
156 }
157
158 // Note the first argument (path to cl source code) will be ignored as they should be embedded in the armcompute.
159 arm_compute::CLKernelLibrary::get().init(".", context, device);
Derek Lamberti836b27b2019-11-20 10:51:57 +0000160 arm_compute::CLScheduler::get().init(context, commandQueue, device, m_Tuner);
surmeh013537c2c2018-05-18 16:31:43 +0100161}
162
163void ClContextControl::ClearClCache()
164{
165 DoLoadOpenClRuntime(true);
166}
167
Ruomei Yan49937f32019-04-25 14:24:05 +0100168armnn::IGpuAccTunedParameters* IGpuAccTunedParameters::CreateRaw(armnn::IGpuAccTunedParameters::Mode mode,
169 armnn::IGpuAccTunedParameters::TuningLevel tuningLevel)
surmeh013537c2c2018-05-18 16:31:43 +0100170{
Ruomei Yan49937f32019-04-25 14:24:05 +0100171 return new ClTunedParameters(mode, tuningLevel);
surmeh013537c2c2018-05-18 16:31:43 +0100172}
173
Ruomei Yan49937f32019-04-25 14:24:05 +0100174armnn::IGpuAccTunedParametersPtr IGpuAccTunedParameters::Create(armnn::IGpuAccTunedParameters::Mode mode,
175 armnn::IGpuAccTunedParameters::TuningLevel tuningLevel)
surmeh013537c2c2018-05-18 16:31:43 +0100176{
Ruomei Yan49937f32019-04-25 14:24:05 +0100177 return IGpuAccTunedParametersPtr(CreateRaw(mode, tuningLevel), &IGpuAccTunedParameters::Destroy);
surmeh013537c2c2018-05-18 16:31:43 +0100178}
179
telsoa01c577f2c2018-08-31 09:22:23 +0100180void IGpuAccTunedParameters::Destroy(IGpuAccTunedParameters* params)
surmeh013537c2c2018-05-18 16:31:43 +0100181{
182 delete params;
183}
184
Ruomei Yan49937f32019-04-25 14:24:05 +0100185ClTunedParameters::ClTunedParameters(armnn::IGpuAccTunedParameters::Mode mode,
186 armnn::IGpuAccTunedParameters::TuningLevel tuningLevel)
surmeh013537c2c2018-05-18 16:31:43 +0100187 : m_Mode(mode)
Ruomei Yan8b194fb2019-05-03 12:10:19 +0100188 , m_TuningLevel(tuningLevel)
surmeh013537c2c2018-05-18 16:31:43 +0100189 , m_Tuner(mode == ClTunedParameters::Mode::UpdateTunedParameters)
surmeh013537c2c2018-05-18 16:31:43 +0100190{
191}
192
193void ClTunedParameters::Load(const char* filename)
194{
surmeh013537c2c2018-05-18 16:31:43 +0100195 try
196 {
197 m_Tuner.load_from_file(filename);
198 }
199 catch (const std::exception& e)
200 {
201 throw armnn::Exception(std::string("Failed to load tuned parameters file '") + filename + "': " +
Derek Lamberti836b27b2019-11-20 10:51:57 +0000202 e.what());
surmeh013537c2c2018-05-18 16:31:43 +0100203 }
surmeh013537c2c2018-05-18 16:31:43 +0100204}
205
206void ClTunedParameters::Save(const char* filename) const
207{
surmeh013537c2c2018-05-18 16:31:43 +0100208 try
209 {
210 m_Tuner.save_to_file(filename);
211 }
212 catch (const std::exception& e)
213 {
214 throw armnn::Exception(std::string("Failed to save tuned parameters file to '") + filename + "': " +
Derek Lamberti836b27b2019-11-20 10:51:57 +0000215 e.what());
surmeh013537c2c2018-05-18 16:31:43 +0100216 }
surmeh013537c2c2018-05-18 16:31:43 +0100217}
218
219} // namespace armnn