blob: 7ab825f59e4c21b6e208924a1fd65fbc2967db59 [file] [log] [blame]
Laurent Carlier749294b2020-06-01 09:03:17 +01001//
surmeh013537c2c2018-05-18 16:31:43 +01002// 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
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010012#include <armnn/utility/Assert.hpp>
Jan Eilers8eb25602020-03-09 12:13:48 +000013#include <armnn/utility/IgnoreUnused.hpp>
14
surmeh013537c2c2018-05-18 16:31:43 +010015#include <arm_compute/core/CL/CLKernelLibrary.h>
16#include <arm_compute/runtime/CL/CLScheduler.h>
surmeh013537c2c2018-05-18 16:31:43 +010017
James Ward47fce872020-09-10 11:57:28 +010018#include <fmt/format.h>
surmeh013537c2c2018-05-18 16:31:43 +010019
surmeh013537c2c2018-05-18 16:31:43 +010020namespace cl
21{
22class Context;
23class CommandQueue;
24class Device;
25}
26
27namespace armnn
28{
29
Derek Lamberti836b27b2019-11-20 10:51:57 +000030ClContextControl::ClContextControl(arm_compute::CLTuner *tuner,
telsoa01c577f2c2018-08-31 09:22:23 +010031 bool profilingEnabled)
Derek Lamberti836b27b2019-11-20 10:51:57 +000032 : m_Tuner(tuner)
telsoa01c577f2c2018-08-31 09:22:23 +010033 , m_ProfilingEnabled(profilingEnabled)
surmeh013537c2c2018-05-18 16:31:43 +010034{
telsoa01c577f2c2018-08-31 09:22:23 +010035 // Ignore m_ProfilingEnabled if unused to avoid compiling problems when ArmCompute is disabled.
Jan Eilers8eb25602020-03-09 12:13:48 +000036 IgnoreUnused(m_ProfilingEnabled);
telsoa01c577f2c2018-08-31 09:22:23 +010037
surmeh013537c2c2018-05-18 16:31:43 +010038 try
39 {
40 std::vector<cl::Platform> platforms;
41 cl::Platform::get(&platforms);
42
telsoa01c577f2c2018-08-31 09:22:23 +010043 // Selects default platform for the first element.
surmeh013537c2c2018-05-18 16:31:43 +010044 cl::Platform::setDefault(platforms[0]);
45
46 std::vector<cl::Device> devices;
47 platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
48
telsoa01c577f2c2018-08-31 09:22:23 +010049 // Selects default device for the first element.
surmeh013537c2c2018-05-18 16:31:43 +010050 cl::Device::setDefault(devices[0]);
51 }
52 catch (const cl::Error& clError)
53 {
James Ward47fce872020-09-10 11:57:28 +010054 throw ClRuntimeUnavailableException(fmt::format(
55 "Could not initialize the CL runtime. Error description: {0}. CL error code: {1}",
56 clError.what(), clError.err()));
surmeh013537c2c2018-05-18 16:31:43 +010057 }
58
telsoa01c577f2c2018-08-31 09:22:23 +010059 // Removes the use of global CL context.
surmeh013537c2c2018-05-18 16:31:43 +010060 cl::Context::setDefault(cl::Context{});
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010061 ARMNN_ASSERT(cl::Context::getDefault()() == NULL);
surmeh013537c2c2018-05-18 16:31:43 +010062
telsoa01c577f2c2018-08-31 09:22:23 +010063 // Removes the use of global CL command queue.
surmeh013537c2c2018-05-18 16:31:43 +010064 cl::CommandQueue::setDefault(cl::CommandQueue{});
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010065 ARMNN_ASSERT(cl::CommandQueue::getDefault()() == NULL);
surmeh013537c2c2018-05-18 16:31:43 +010066
telsoa01c577f2c2018-08-31 09:22:23 +010067 // Always load the OpenCL runtime.
surmeh013537c2c2018-05-18 16:31:43 +010068 LoadOpenClRuntime();
surmeh013537c2c2018-05-18 16:31:43 +010069}
70
71ClContextControl::~ClContextControl()
72{
telsoa01c577f2c2018-08-31 09:22:23 +010073 // Load the OpencCL runtime without the tuned parameters to free the memory for them.
surmeh013537c2c2018-05-18 16:31:43 +010074 try
75 {
76 UnloadOpenClRuntime();
77 }
78 catch (const cl::Error& clError)
79 {
telsoa01c577f2c2018-08-31 09:22:23 +010080 // This should not happen, it is ignored if it does.
surmeh013537c2c2018-05-18 16:31:43 +010081
82 // Coverity fix: BOOST_LOG_TRIVIAL (previously used here to report the error) may throw an
83 // exception of type std::length_error.
84 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
85 std::cerr << "A CL error occurred unloading the runtime tuner parameters: "
86 << clError.what() << ". CL error code is: " << clError.err() << std::endl;
87 }
surmeh013537c2c2018-05-18 16:31:43 +010088}
89
90void ClContextControl::LoadOpenClRuntime()
91{
92 DoLoadOpenClRuntime(true);
93}
94
95void ClContextControl::UnloadOpenClRuntime()
96{
97 DoLoadOpenClRuntime(false);
98}
99
Derek Lamberti836b27b2019-11-20 10:51:57 +0000100void ClContextControl::DoLoadOpenClRuntime(bool updateTunedParameters)
surmeh013537c2c2018-05-18 16:31:43 +0100101{
surmeh013537c2c2018-05-18 16:31:43 +0100102 cl::Device device = cl::Device::getDefault();
103 cl::Context context;
104 cl::CommandQueue commandQueue;
105
James Conroy663c1842019-11-01 15:21:48 +0000106 if (arm_compute::CLScheduler::get().is_initialised() && arm_compute::CLScheduler::get().context()() != NULL)
surmeh013537c2c2018-05-18 16:31:43 +0100107 {
telsoa01c577f2c2018-08-31 09:22:23 +0100108 // Wait for all queued CL requests to finish before reinitialising it.
surmeh013537c2c2018-05-18 16:31:43 +0100109 arm_compute::CLScheduler::get().sync();
110 }
111
112 try
113 {
114 arm_compute::CLKernelLibrary::get().clear_programs_cache();
telsoa01c577f2c2018-08-31 09:22:23 +0100115 // 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 +0100116 // context references); it is initialised again, with a proper context, later.
117 arm_compute::CLScheduler::get().init(context, commandQueue, device);
118 arm_compute::CLKernelLibrary::get().init(".", context, device);
119
120 {
121 //
telsoa01c577f2c2018-08-31 09:22:23 +0100122 // Here we replace the context with a new one in which
123 // the memory leak checks show it as an extra allocation but
124 // because of the scope of the leak checks, it doesn't count
surmeh013537c2c2018-05-18 16:31:43 +0100125 // the disposal of the original object. On the other hand it
126 // does count the creation of this context which it flags
127 // as a memory leak. By adding the following line we prevent
128 // this to happen.
129 //
130 ARMNN_DISABLE_LEAK_CHECKING_IN_SCOPE();
131 context = cl::Context(device);
132 }
133
telsoa01c577f2c2018-08-31 09:22:23 +0100134 // NOTE: In this specific case profiling has to be enabled on the command queue
135 // in order for the CLTuner to work.
Derek Lamberti836b27b2019-11-20 10:51:57 +0000136 bool profilingNeededForClTuner = updateTunedParameters && m_Tuner &&
137 m_Tuner->tune_new_kernels();
surmeh013537c2c2018-05-18 16:31:43 +0100138
telsoa01c577f2c2018-08-31 09:22:23 +0100139 if (m_ProfilingEnabled || profilingNeededForClTuner)
surmeh013537c2c2018-05-18 16:31:43 +0100140 {
telsoa01c577f2c2018-08-31 09:22:23 +0100141 // Create a new queue with profiling enabled.
surmeh013537c2c2018-05-18 16:31:43 +0100142 commandQueue = cl::CommandQueue(context, device, CL_QUEUE_PROFILING_ENABLE);
143 }
144 else
145 {
telsoa01c577f2c2018-08-31 09:22:23 +0100146 // Use default queue.
surmeh013537c2c2018-05-18 16:31:43 +0100147 commandQueue = cl::CommandQueue(context, device);
148 }
149 }
150 catch (const cl::Error& clError)
151 {
James Ward47fce872020-09-10 11:57:28 +0100152 throw ClRuntimeUnavailableException(fmt::format(
153 "Could not initialize the CL runtime. Error description: {0}. CL error code: {1}",
154 clError.what(), clError.err()));
surmeh013537c2c2018-05-18 16:31:43 +0100155 }
156
157 // Note the first argument (path to cl source code) will be ignored as they should be embedded in the armcompute.
158 arm_compute::CLKernelLibrary::get().init(".", context, device);
Derek Lamberti836b27b2019-11-20 10:51:57 +0000159 arm_compute::CLScheduler::get().init(context, commandQueue, device, m_Tuner);
surmeh013537c2c2018-05-18 16:31:43 +0100160}
161
162void ClContextControl::ClearClCache()
163{
164 DoLoadOpenClRuntime(true);
165}
166
Ruomei Yan49937f32019-04-25 14:24:05 +0100167armnn::IGpuAccTunedParameters* IGpuAccTunedParameters::CreateRaw(armnn::IGpuAccTunedParameters::Mode mode,
168 armnn::IGpuAccTunedParameters::TuningLevel tuningLevel)
surmeh013537c2c2018-05-18 16:31:43 +0100169{
Ruomei Yan49937f32019-04-25 14:24:05 +0100170 return new ClTunedParameters(mode, tuningLevel);
surmeh013537c2c2018-05-18 16:31:43 +0100171}
172
Ruomei Yan49937f32019-04-25 14:24:05 +0100173armnn::IGpuAccTunedParametersPtr IGpuAccTunedParameters::Create(armnn::IGpuAccTunedParameters::Mode mode,
174 armnn::IGpuAccTunedParameters::TuningLevel tuningLevel)
surmeh013537c2c2018-05-18 16:31:43 +0100175{
Ruomei Yan49937f32019-04-25 14:24:05 +0100176 return IGpuAccTunedParametersPtr(CreateRaw(mode, tuningLevel), &IGpuAccTunedParameters::Destroy);
surmeh013537c2c2018-05-18 16:31:43 +0100177}
178
telsoa01c577f2c2018-08-31 09:22:23 +0100179void IGpuAccTunedParameters::Destroy(IGpuAccTunedParameters* params)
surmeh013537c2c2018-05-18 16:31:43 +0100180{
181 delete params;
182}
183
Ruomei Yan49937f32019-04-25 14:24:05 +0100184ClTunedParameters::ClTunedParameters(armnn::IGpuAccTunedParameters::Mode mode,
185 armnn::IGpuAccTunedParameters::TuningLevel tuningLevel)
surmeh013537c2c2018-05-18 16:31:43 +0100186 : m_Mode(mode)
Ruomei Yan8b194fb2019-05-03 12:10:19 +0100187 , m_TuningLevel(tuningLevel)
surmeh013537c2c2018-05-18 16:31:43 +0100188 , m_Tuner(mode == ClTunedParameters::Mode::UpdateTunedParameters)
surmeh013537c2c2018-05-18 16:31:43 +0100189{
190}
191
192void ClTunedParameters::Load(const char* filename)
193{
surmeh013537c2c2018-05-18 16:31:43 +0100194 try
195 {
196 m_Tuner.load_from_file(filename);
197 }
198 catch (const std::exception& e)
199 {
200 throw armnn::Exception(std::string("Failed to load tuned parameters file '") + filename + "': " +
Derek Lamberti836b27b2019-11-20 10:51:57 +0000201 e.what());
surmeh013537c2c2018-05-18 16:31:43 +0100202 }
surmeh013537c2c2018-05-18 16:31:43 +0100203}
204
205void ClTunedParameters::Save(const char* filename) const
206{
surmeh013537c2c2018-05-18 16:31:43 +0100207 try
208 {
209 m_Tuner.save_to_file(filename);
210 }
211 catch (const std::exception& e)
212 {
213 throw armnn::Exception(std::string("Failed to save tuned parameters file to '") + filename + "': " +
Derek Lamberti836b27b2019-11-20 10:51:57 +0000214 e.what());
surmeh013537c2c2018-05-18 16:31:43 +0100215 }
surmeh013537c2c2018-05-18 16:31:43 +0100216}
217
218} // namespace armnn