1 /* 2 * Copyright (c) 2017-2021 Arm Limited. 3 * 4 * SPDX-License-Identifier: MIT 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 #ifndef ARM_COMPUTE_TEST_CL_HELPER_H 25 #define ARM_COMPUTE_TEST_CL_HELPER_H 26 27 #include "arm_compute/runtime/CL/CLScheduler.h" 28 #include "arm_compute/runtime/CL/ICLSimpleFunction.h" 29 #include "arm_compute/runtime/CL/functions/CLFill.h" 30 #include "arm_compute/runtime/IFunction.h" 31 #include "src/core/CL/kernels/CLFillBorderKernel.h" 32 #include "src/gpu/cl/IClOperator.h" 33 #include "src/gpu/cl/operators/ClFill.h" 34 35 #include "src/core/CL/ICLKernel.h" 36 #include "support/Cast.h" 37 38 #include <memory> 39 40 namespace arm_compute 41 { 42 namespace test 43 { 44 /** This template synthetizes a simple IOperator which runs the given kernel K */ 45 template <typename K> 46 class CLSynthetizeOperator : public opencl::IClOperator 47 { 48 public: 49 /** Configure the kernel. 50 * 51 * @param[in] args Configuration arguments. 52 */ 53 template <typename... Args> configure(Args &&...args)54 void configure(Args &&... args) 55 { 56 auto k = std::make_unique<K>(); 57 k->configure(CLKernelLibrary::get().get_compile_context(), std::forward<Args>(args)...); 58 _kernel = std::move(k); 59 } 60 /** Configure the kernel setting the GPU target as well 61 * 62 * @param[in] gpu_target GPUTarget to set 63 * @param[in] args Configuration arguments. 64 */ 65 template <typename... Args> configure(GPUTarget gpu_target,Args &&...args)66 void configure(GPUTarget gpu_target, Args &&... args) 67 { 68 auto k = std::make_unique<K>(); 69 k->set_target(gpu_target); 70 k->configure(CLKernelLibrary::get().get_compile_context(), std::forward<Args>(args)...); 71 _kernel = std::move(k); 72 } 73 /** Validate input arguments 74 * 75 * @param[in] args Configuration arguments. 76 */ 77 template <typename... Args> validate(Args &&...args)78 static Status validate(Args &&... args) 79 { 80 return K::validate(std::forward<Args>(args)...); 81 } 82 }; 83 84 /** As above but this also initializes to zero the input tensor */ 85 template <typename K, int bordersize> 86 class CLSynthetizeOperatorInitOutputWithZeroAndWithZeroConstantBorder : public opencl::IClOperator 87 { 88 public: 89 /** Configure the kernel. 90 * 91 * @param[in] first First input argument. 92 * @param[in] second Second input argument. 93 * @param[in] args Rest of the configuration arguments. 94 */ 95 template <typename T, typename... Args> configure(T first,T second,Args &&...args)96 void configure(T first, T second, Args &&... args) 97 { 98 auto cctx = CLKernelLibrary::get().get_compile_context(); 99 auto k = std::make_unique<K>(); 100 k->set_target(CLScheduler::get().target()); 101 k->configure(cctx, first, second, std::forward<Args>(args)...); 102 _kernel = std::move(k); 103 _border_handler.configure(cctx, first, BorderSize(bordersize), BorderMode::CONSTANT, PixelValue()); 104 _fill.configure(cctx, second, PixelValue()); 105 } 106 107 // Inherited method overridden: run(ITensorPack & tensors)108 void run(ITensorPack &tensors) override final 109 { 110 ARM_COMPUTE_ERROR_ON_MSG(!_kernel, "The CL kernel or function isn't configured"); 111 112 ITensorPack fill_pack = { { ACL_SRC, tensors.get_tensor(TensorType::ACL_DST) } }; 113 _fill.run(fill_pack); 114 CLScheduler::get().enqueue_op(_border_handler, tensors); 115 CLScheduler::get().enqueue_op(*_kernel, tensors); 116 } 117 118 private: 119 opencl::ClFill _fill{}; /**< Kernel to initialize the tensor */ 120 CLFillBorderKernel _border_handler{}; /**< Kernel to handle borders */ 121 std::unique_ptr<ICLKernel> _kernel{}; /**< Kernel to run */ 122 }; 123 124 /** This template synthetizes an ICLSimpleFunction which runs the given kernel K */ 125 template <typename K> 126 class CLSynthetizeFunction : public ICLSimpleFunction 127 { 128 public: 129 /** Configure the kernel. 130 * 131 * @param[in] args Configuration arguments. 132 */ 133 template <typename... Args> configure(Args &&...args)134 void configure(Args &&... args) 135 { 136 auto k = std::make_unique<K>(); 137 k->configure(std::forward<Args>(args)...); 138 _kernel = std::move(k); 139 } 140 /** Configure the kernel setting the GPU target as well 141 * 142 * @param[in] gpu_target GPUTarget to set 143 * @param[in] args Configuration arguments. 144 */ 145 template <typename... Args> configure(GPUTarget gpu_target,Args &&...args)146 void configure(GPUTarget gpu_target, Args &&... args) 147 { 148 auto k = std::make_unique<K>(); 149 k->set_target(gpu_target); 150 k->configure(std::forward<Args>(args)...); 151 _kernel = std::move(k); 152 } 153 /** Validate input arguments 154 * 155 * @param[in] args Configuration arguments. 156 */ 157 template <typename... Args> validate(Args &&...args)158 static Status validate(Args &&... args) 159 { 160 return K::validate(std::forward<Args>(args)...); 161 } 162 }; 163 164 /** As above but this also setups a Zero border on the input tensor of the specified bordersize */ 165 template <typename K, int bordersize> 166 class CLSynthetizeFunctionWithZeroConstantBorder : public ICLSimpleFunction 167 { 168 public: 169 /** Configure the kernel. 170 * 171 * @param[in] first First configuration argument. 172 * @param[in] args Rest of the configuration arguments. 173 */ 174 template <typename T, typename... Args> configure(T first,Args &&...args)175 void configure(T first, Args &&... args) 176 { 177 auto k = std::make_unique<K>(); 178 k->configure(first, std::forward<Args>(args)...); 179 _kernel = std::move(k); 180 _border_handler->configure(first, BorderSize(bordersize), BorderMode::CONSTANT, PixelValue()); 181 } 182 }; 183 184 /** As above but this also initializes to zero the input tensor */ 185 template <typename K, int bordersize> 186 class CLSynthetizeFunctionInitOutputWithZeroAndWithZeroConstantBorder : public IFunction 187 { 188 public: 189 /** Configure the kernel. 190 * 191 * @param[in] first First input argument. 192 * @param[in] second Second input argument. 193 * @param[in] args Rest of the configuration arguments. 194 */ 195 template <typename T, typename... Args> configure(T first,T second,Args &&...args)196 void configure(T first, T second, Args &&... args) 197 { 198 auto k = std::make_unique<K>(); 199 k->set_target(CLScheduler::get().target()); 200 k->configure(first, second, std::forward<Args>(args)...); 201 _kernel = std::move(k); 202 _border_handler.configure(first, BorderSize(bordersize), BorderMode::CONSTANT, PixelValue()); 203 _fill.configure(second, PixelValue()); 204 } 205 206 // Inherited method overridden: run()207 void run() override final 208 { 209 ARM_COMPUTE_ERROR_ON_MSG(!_kernel, "The CL kernel or function isn't configured"); 210 211 _fill.run(); 212 CLScheduler::get().enqueue(_border_handler, false); 213 CLScheduler::get().enqueue(*_kernel); 214 } 215 216 private: 217 CLFill _fill{}; /**< Kernel to initialize the tensor */ 218 CLFillBorderKernel _border_handler{}; /**< Kernel to handle borders */ 219 std::unique_ptr<ICLKernel> _kernel{}; /**< Kernel to run */ 220 }; 221 222 /** As above but this also setups a Zero border on the input tensor of the kernel's bordersize */ 223 template <typename K> 224 class ClSynthetizeOperatorWithBorder : public opencl::IClOperator 225 { 226 public: 227 /** Configure the kernel. 228 * 229 * @param[in] first First configuration argument. 230 * @param[in] args Rest of the configuration arguments. 231 */ 232 template <typename T, typename... Args> configure(T first,Args &&...args)233 void configure(T first, Args &&... args) 234 { 235 auto k = std::make_unique<K>(); 236 k->configure(CLKernelLibrary::get().get_compile_context(), first, std::forward<Args>(args)...); 237 _kernel = std::move(k); 238 239 auto b = std::make_unique<CLFillBorderKernel>(); 240 b->configure(CLKernelLibrary::get().get_compile_context(), first, BorderSize(_kernel->border_size()), BorderMode::CONSTANT, PixelValue()); 241 _border_handler = std::move(b); 242 } 243 run(ITensorPack & tensors)244 void run(ITensorPack &tensors) override 245 { 246 CLScheduler::get().enqueue(*_border_handler); 247 CLScheduler::get().enqueue_op(*_kernel, tensors); 248 } 249 250 private: 251 std::unique_ptr<ICLKernel> _border_handler{ nullptr }; /**< Kernel to handle borders */ 252 std::unique_ptr<ICLKernel> _kernel{}; /**< Kernel to run */ 253 }; 254 } // namespace test 255 } // namespace arm_compute 256 #endif /* ARM_COMPUTE_TEST_CL_HELPER_H */ 257