blob: 20223ae384482cfc4f63821777165df8dfc7a338 [file] [log] [blame]
Laurent Carlier749294b2020-06-01 09:03:17 +01001//
Colm Donelanb4ef1632024-02-01 15:00:43 +00002// Copyright © 2017, 2024 Arm Ltd and Contributors. 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
surmeh013537c2c2018-05-18 16:31:43 +010012#include <arm_compute/core/CL/CLKernelLibrary.h>
13#include <arm_compute/runtime/CL/CLScheduler.h>
surmeh013537c2c2018-05-18 16:31:43 +010014
James Ward47fce872020-09-10 11:57:28 +010015#include <fmt/format.h>
surmeh013537c2c2018-05-18 16:31:43 +010016
surmeh013537c2c2018-05-18 16:31:43 +010017namespace cl
18{
19class Context;
20class CommandQueue;
21class Device;
22}
23
24namespace armnn
25{
26
Derek Lamberti836b27b2019-11-20 10:51:57 +000027ClContextControl::ClContextControl(arm_compute::CLTuner *tuner,
Finn Williams40646322021-02-11 16:16:42 +000028 arm_compute::CLGEMMHeuristicsHandle* heuristicsHandle,
telsoa01c577f2c2018-08-31 09:22:23 +010029 bool profilingEnabled)
Derek Lamberti836b27b2019-11-20 10:51:57 +000030 : m_Tuner(tuner)
Finn Williams40646322021-02-11 16:16:42 +000031 , m_HeuristicsHandle(heuristicsHandle)
telsoa01c577f2c2018-08-31 09:22:23 +010032 , m_ProfilingEnabled(profilingEnabled)
surmeh013537c2c2018-05-18 16:31:43 +010033{
surmeh013537c2c2018-05-18 16:31:43 +010034 try
35 {
36 std::vector<cl::Platform> platforms;
37 cl::Platform::get(&platforms);
38
telsoa01c577f2c2018-08-31 09:22:23 +010039 // Selects default platform for the first element.
surmeh013537c2c2018-05-18 16:31:43 +010040 cl::Platform::setDefault(platforms[0]);
41
42 std::vector<cl::Device> devices;
43 platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
44
telsoa01c577f2c2018-08-31 09:22:23 +010045 // Selects default device for the first element.
surmeh013537c2c2018-05-18 16:31:43 +010046 cl::Device::setDefault(devices[0]);
47 }
48 catch (const cl::Error& clError)
49 {
James Ward47fce872020-09-10 11:57:28 +010050 throw ClRuntimeUnavailableException(fmt::format(
51 "Could not initialize the CL runtime. Error description: {0}. CL error code: {1}",
52 clError.what(), clError.err()));
surmeh013537c2c2018-05-18 16:31:43 +010053 }
54
telsoa01c577f2c2018-08-31 09:22:23 +010055 // Removes the use of global CL context.
surmeh013537c2c2018-05-18 16:31:43 +010056 cl::Context::setDefault(cl::Context{});
surmeh013537c2c2018-05-18 16:31:43 +010057
telsoa01c577f2c2018-08-31 09:22:23 +010058 // Removes the use of global CL command queue.
surmeh013537c2c2018-05-18 16:31:43 +010059 cl::CommandQueue::setDefault(cl::CommandQueue{});
surmeh013537c2c2018-05-18 16:31:43 +010060
telsoa01c577f2c2018-08-31 09:22:23 +010061 // Always load the OpenCL runtime.
surmeh013537c2c2018-05-18 16:31:43 +010062 LoadOpenClRuntime();
surmeh013537c2c2018-05-18 16:31:43 +010063}
64
65ClContextControl::~ClContextControl()
66{
telsoa01c577f2c2018-08-31 09:22:23 +010067 // Load the OpencCL runtime without the tuned parameters to free the memory for them.
surmeh013537c2c2018-05-18 16:31:43 +010068 try
69 {
70 UnloadOpenClRuntime();
71 }
72 catch (const cl::Error& clError)
73 {
telsoa01c577f2c2018-08-31 09:22:23 +010074 // This should not happen, it is ignored if it does.
surmeh013537c2c2018-05-18 16:31:43 +010075
76 // Coverity fix: BOOST_LOG_TRIVIAL (previously used here to report the error) may throw an
77 // exception of type std::length_error.
78 // Using stderr instead in this context as there is no point in nesting try-catch blocks here.
79 std::cerr << "A CL error occurred unloading the runtime tuner parameters: "
80 << clError.what() << ". CL error code is: " << clError.err() << std::endl;
81 }
surmeh013537c2c2018-05-18 16:31:43 +010082}
83
84void ClContextControl::LoadOpenClRuntime()
85{
86 DoLoadOpenClRuntime(true);
87}
88
89void ClContextControl::UnloadOpenClRuntime()
90{
91 DoLoadOpenClRuntime(false);
92}
93
Derek Lamberti836b27b2019-11-20 10:51:57 +000094void ClContextControl::DoLoadOpenClRuntime(bool updateTunedParameters)
surmeh013537c2c2018-05-18 16:31:43 +010095{
surmeh013537c2c2018-05-18 16:31:43 +010096 cl::Device device = cl::Device::getDefault();
97 cl::Context context;
98 cl::CommandQueue commandQueue;
99
James Conroy663c1842019-11-01 15:21:48 +0000100 if (arm_compute::CLScheduler::get().is_initialised() && arm_compute::CLScheduler::get().context()() != NULL)
surmeh013537c2c2018-05-18 16:31:43 +0100101 {
telsoa01c577f2c2018-08-31 09:22:23 +0100102 // Wait for all queued CL requests to finish before reinitialising it.
surmeh013537c2c2018-05-18 16:31:43 +0100103 arm_compute::CLScheduler::get().sync();
104 }
105
106 try
107 {
108 arm_compute::CLKernelLibrary::get().clear_programs_cache();
telsoa01c577f2c2018-08-31 09:22:23 +0100109 // 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 +0100110 // context references); it is initialised again, with a proper context, later.
111 arm_compute::CLScheduler::get().init(context, commandQueue, device);
112 arm_compute::CLKernelLibrary::get().init(".", context, device);
113
114 {
115 //
telsoa01c577f2c2018-08-31 09:22:23 +0100116 // Here we replace the context with a new one in which
117 // the memory leak checks show it as an extra allocation but
118 // because of the scope of the leak checks, it doesn't count
surmeh013537c2c2018-05-18 16:31:43 +0100119 // the disposal of the original object. On the other hand it
120 // does count the creation of this context which it flags
121 // as a memory leak. By adding the following line we prevent
122 // this to happen.
123 //
124 ARMNN_DISABLE_LEAK_CHECKING_IN_SCOPE();
125 context = cl::Context(device);
126 }
127
telsoa01c577f2c2018-08-31 09:22:23 +0100128 // NOTE: In this specific case profiling has to be enabled on the command queue
129 // in order for the CLTuner to work.
Derek Lamberti836b27b2019-11-20 10:51:57 +0000130 bool profilingNeededForClTuner = updateTunedParameters && m_Tuner &&
131 m_Tuner->tune_new_kernels();
surmeh013537c2c2018-05-18 16:31:43 +0100132
telsoa01c577f2c2018-08-31 09:22:23 +0100133 if (m_ProfilingEnabled || profilingNeededForClTuner)
surmeh013537c2c2018-05-18 16:31:43 +0100134 {
telsoa01c577f2c2018-08-31 09:22:23 +0100135 // Create a new queue with profiling enabled.
surmeh013537c2c2018-05-18 16:31:43 +0100136 commandQueue = cl::CommandQueue(context, device, CL_QUEUE_PROFILING_ENABLE);
137 }
138 else
139 {
telsoa01c577f2c2018-08-31 09:22:23 +0100140 // Use default queue.
surmeh013537c2c2018-05-18 16:31:43 +0100141 commandQueue = cl::CommandQueue(context, device);
142 }
143 }
144 catch (const cl::Error& clError)
145 {
James Ward47fce872020-09-10 11:57:28 +0100146 throw ClRuntimeUnavailableException(fmt::format(
147 "Could not initialize the CL runtime. Error description: {0}. CL error code: {1}",
148 clError.what(), clError.err()));
surmeh013537c2c2018-05-18 16:31:43 +0100149 }
150
151 // Note the first argument (path to cl source code) will be ignored as they should be embedded in the armcompute.
152 arm_compute::CLKernelLibrary::get().init(".", context, device);
Finn Williams40646322021-02-11 16:16:42 +0000153 arm_compute::CLScheduler::get().init(context, commandQueue, device, m_Tuner, m_HeuristicsHandle);
surmeh013537c2c2018-05-18 16:31:43 +0100154}
155
156void ClContextControl::ClearClCache()
157{
158 DoLoadOpenClRuntime(true);
159}
160
surmeh013537c2c2018-05-18 16:31:43 +0100161} // namespace armnn