Eigen-Contrib  5.0.1
 
Loading...
Searching...
No Matches
TensorConvolutionSycl.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Mehdi Goli Codeplay Software Ltd.
5// Ralph Potter Codeplay Software Ltd.
6// Luke Iwanski Codeplay Software Ltd.
7// Contact: <eigen@codeplay.com>
8// Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com>
9// SPDX-License-Identifier: MPL-2.0
10
11//
12// This Source Code Form is subject to the terms of the Mozilla
13// Public License v. 2.0. If a copy of the MPL was not distributed
14// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
15
16#ifndef EIGEN_TENSOR_TENSOR_CONVOLUTION_SYCL_H
17#define EIGEN_TENSOR_TENSOR_CONVOLUTION_SYCL_H
18
19// IWYU pragma: private
20#include "./InternalHeaderCheck.h"
21
22namespace Eigen {
23
24enum class convolution_type { CONV1D, CONV2D, CONV3D };
25template <typename Evaluator, typename CoeffReturnType, typename KernelType, typename Index, typename InputDims,
26 typename Kernel_accessor, typename Buffer_accessor, convolution_type Conv_Dim>
27struct EigenConvolutionKernel;
28template <typename Evaluator, typename CoeffReturnType, typename KernelType, typename Index, typename InputDims,
29 typename Kernel_accessor, typename Buffer_accessor>
30struct EigenConvolutionKernel<Evaluator, CoeffReturnType, KernelType, Index, InputDims, Kernel_accessor,
31 Buffer_accessor, convolution_type::CONV1D> {
32 typedef cl::sycl::accessor<CoeffReturnType, 1, cl::sycl::access::mode::read_write, cl::sycl::access::target::local>
33 Local_accessor;
34 Local_accessor local_acc;
35 Evaluator device_evaluator;
36 Kernel_accessor kernel_filter;
37 Buffer_accessor buffer_acc;
38 internal::IndexMapper<Index, InputDims, 1, Evaluator::Layout> indexMapper;
39 const size_t kernelSize;
40 const cl::sycl::range<2> input_range;
41 EigenConvolutionKernel(Local_accessor local_acc_, Evaluator device_evaluator_, Kernel_accessor kernel_filter_,
42 Buffer_accessor buffer_acc_,
43 internal::IndexMapper<Index, InputDims, 1, Evaluator::Layout> indexMapper_,
44 const size_t kernelSize_, const cl::sycl::range<2> input_range_)
45 : local_acc(local_acc_),
46 device_evaluator(device_evaluator_),
47 kernel_filter(kernel_filter_),
48 buffer_acc(buffer_acc_),
49 indexMapper(indexMapper_),
50 kernelSize(kernelSize_),
51 input_range(input_range_) {}
52
53 template <typename BooleanDim2>
54 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool boundary_check(const BooleanDim2 boolean_check) const {
55 return boolean_check[0] && boolean_check[1];
56 }
57 void operator()(cl::sycl::nd_item<2> itemID) const {
58 auto buffer_ptr = buffer_acc;
59 auto kernel_ptr = kernel_filter;
60 // the required row to be calculated for each plane in shared memory
61 const size_t num_input = (itemID.get_local_range()[0] + kernelSize - 1);
62 const size_t plane_kernel_offset = itemID.get_local_id(1) * num_input;
63 const size_t input_offset = itemID.get_group(0) * itemID.get_local_range()[0];
64 const size_t plane_tensor_offset = indexMapper.mapGpuInputPlaneToTensorInputOffset(itemID.get_global_id(1));
66 for (size_t i = itemID.get_local_id(0); i < num_input; i += itemID.get_local_range()[0]) {
67 const size_t local_index = i + plane_kernel_offset;
68 const size_t tensor_index =
69 plane_tensor_offset + indexMapper.mapGpuInputKernelToTensorInputOffset(i + input_offset);
70
71 local_acc[local_index] =
72 (((i + input_offset) < (input_range[0] + kernelSize - 1)) && itemID.get_global_id(1) < input_range[1])
73 ? device_evaluator.coeff(tensor_index)
74 : CoeffReturnType(0);
75 }
76
77 itemID.barrier(cl::sycl::access::fence_space::local_space);
78
79 // calculate the convolution // output start x
80 const size_t first_output_start = itemID.get_group(0) * (itemID.get_local_range()[0]);
81 if (boundary_check(itemID.get_global_id() < input_range)) {
82 CoeffReturnType result = static_cast<CoeffReturnType>(0);
83 const size_t index = plane_kernel_offset + itemID.get_local_id(0);
84 for (size_t k = 0; k < kernelSize; ++k) {
85 result += (local_acc[k + index] * kernel_ptr[k]);
86 }
87 const size_t tensor_index =
88 indexMapper.mapGpuOutputPlaneToTensorOutputOffset(itemID.get_global_id(1)) +
89 indexMapper.mapGpuOutputKernelToTensorOutputOffset(itemID.get_local_id(0) + first_output_start);
90 buffer_ptr[tensor_index] = result;
91 }
92 }
93};
94
95template <typename Evaluator, typename CoeffReturnType, typename KernelType, typename Index, typename InputDims,
96 typename Kernel_accessor, typename Buffer_accessor>
97struct EigenConvolutionKernel<Evaluator, CoeffReturnType, KernelType, Index, InputDims, Kernel_accessor,
98 Buffer_accessor, convolution_type::CONV2D> {
99 typedef cl::sycl::accessor<CoeffReturnType, 1, cl::sycl::access::mode::read_write, cl::sycl::access::target::local>
100 Local_accessor;
101 Local_accessor local_acc;
102 Evaluator device_evaluator;
103 Kernel_accessor kernel_filter;
104 Buffer_accessor buffer_acc;
105 internal::IndexMapper<Index, InputDims, 2, Evaluator::Layout> indexMapper;
106 const cl::sycl::range<2> kernel_size;
107 const cl::sycl::range<3> input_range;
108 EigenConvolutionKernel(Local_accessor local_acc_, Evaluator device_evaluator_, Kernel_accessor kernel_filter_,
109 Buffer_accessor buffer_acc_,
110 internal::IndexMapper<Index, InputDims, 2, Evaluator::Layout> indexMapper_,
111 const cl::sycl::range<2> kernel_size_, const cl::sycl::range<3> input_range_)
112 : local_acc(local_acc_),
113 device_evaluator(device_evaluator_),
114 kernel_filter(kernel_filter_),
115 buffer_acc(buffer_acc_),
116 indexMapper(indexMapper_),
117 kernel_size(kernel_size_),
118 input_range(input_range_) {}
119 template <typename BooleanDim3>
120 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool boundary_check(const BooleanDim3 boolean_check) const {
121 return boolean_check[0] && boolean_check[1] && boolean_check[2];
122 }
123
124 void operator()(cl::sycl::nd_item<3> itemID) const {
125 auto buffer_ptr = buffer_acc;
126 auto kernel_ptr = kernel_filter;
127 // the required row to be calculated for each plane in shared memory
128 const auto num_input = cl::sycl::range<2>{
129 (cl::sycl::range<2>(itemID.get_local_range()[0], itemID.get_local_range()[1]) + kernel_size - 1)};
130
131 const size_t plane_input_offset = indexMapper.mapGpuInputPlaneToTensorInputOffset(itemID.get_global_id(2));
132 const size_t plane_kernel_offset = itemID.get_local_id(2) * num_input[1];
133
134 const auto input_offset = cl::sycl::range<2>{itemID.get_group(0) * itemID.get_local_range()[0],
135 itemID.get_group(1) * itemID.get_local_range()[1]};
136
137 // fill the local memory
138 bool in_range_dim2 = itemID.get_global_id(2) < input_range[2];
139 for (size_t j = itemID.get_local_id(1); j < num_input[1]; j += itemID.get_local_range()[1]) {
140 const size_t local_input_offset = num_input[0] * (j + plane_kernel_offset);
141 bool in_range_dim1 = ((j + input_offset[1]) < (input_range[1] + kernel_size[1] - 1));
142 for (size_t i = itemID.get_local_id(0); i < num_input[0]; i += itemID.get_local_range()[0]) {
143 const size_t local_index = i + local_input_offset;
144 const size_t tensor_index = plane_input_offset + indexMapper.mapGpuInputKernelToTensorInputOffset(
145 i + input_offset[0], j + input_offset[1]);
146 local_acc[local_index] =
147 (((i + input_offset[0]) < (input_range[0] + kernel_size[0] - 1)) && in_range_dim1 && in_range_dim2)
148 ? device_evaluator.coeff(tensor_index)
149 : CoeffReturnType(0);
150 }
151 }
152
153 itemID.barrier(cl::sycl::access::fence_space::local_space);
154
155 // output offset start for each thread
156 const auto output_offset = cl::sycl::range<2>{itemID.get_group(0) * itemID.get_local_range()[0],
157 itemID.get_group(1) * itemID.get_local_range()[1]};
158
159 if (boundary_check(itemID.get_global_id() < input_range)) {
160 CoeffReturnType result = static_cast<CoeffReturnType>(0);
161
162 for (size_t j = 0; j < kernel_size[1]; j++) {
163 size_t kernel_offset = kernel_size[0] * j;
164 const size_t index =
165 (num_input[0] * (plane_kernel_offset + j + itemID.get_local_id(1))) + itemID.get_local_id(0);
166 for (size_t i = 0; i < kernel_size[0]; i++) {
167 result += (local_acc[i + index] * kernel_ptr[i + kernel_offset]);
168 }
169 }
170 const size_t tensor_index =
171 indexMapper.mapGpuOutputPlaneToTensorOutputOffset(itemID.get_global_id(2)) +
172 indexMapper.mapGpuOutputKernelToTensorOutputOffset(itemID.get_local_id(0) + output_offset[0],
173 itemID.get_local_id(1) + output_offset[1]);
174
175 buffer_ptr[tensor_index] = result;
176 }
177 }
178};
179
180template <typename Evaluator, typename CoeffReturnType, typename KernelType, typename Index, typename InputDims,
181 typename Kernel_accessor, typename Buffer_accessor>
182struct EigenConvolutionKernel<Evaluator, CoeffReturnType, KernelType, Index, InputDims, Kernel_accessor,
183 Buffer_accessor, convolution_type::CONV3D> {
184 typedef cl::sycl::accessor<CoeffReturnType, 1, cl::sycl::access::mode::read_write, cl::sycl::access::target::local>
185 Local_accessor;
186 Local_accessor local_acc;
187 Evaluator device_evaluator;
188 Kernel_accessor kernel_filter;
189 Buffer_accessor buffer_acc;
190 internal::IndexMapper<Index, InputDims, 3, Evaluator::Layout> indexMapper;
191 const cl::sycl::range<3> kernel_size;
192 const cl::sycl::range<3> input_range;
193 const size_t numP;
194
195 EigenConvolutionKernel(Local_accessor local_acc_, Evaluator device_evaluator_, Kernel_accessor kernel_filter_,
196 Buffer_accessor buffer_acc_,
197 internal::IndexMapper<Index, InputDims, 3, Evaluator::Layout> indexMapper_,
198 const cl::sycl::range<3> kernel_size_, const cl::sycl::range<3> input_range_,
199 const size_t numP_)
200 : local_acc(local_acc_),
201 device_evaluator(device_evaluator_),
202 kernel_filter(kernel_filter_),
203 buffer_acc(buffer_acc_),
204 indexMapper(indexMapper_),
205 kernel_size(kernel_size_),
206 input_range(input_range_),
207 numP(numP_) {}
208 template <typename BooleanDim3>
209 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool boundary_check(const BooleanDim3 boolean_check) const {
210 return boolean_check[0] && boolean_check[1] && boolean_check[2];
211 }
212 void operator()(cl::sycl::nd_item<3> itemID) const {
213 auto buffer_ptr = buffer_acc;
214 auto kernel_ptr = kernel_filter;
215 const auto num_input = cl::sycl::range<3>{itemID.get_local_range() + kernel_size - 1};
216
217 const auto input_offset = cl::sycl::range<3>{itemID.get_group().get_id() * itemID.get_local_range()};
218
219 const auto output_offset =
220 cl::sycl::range<3>{itemID.get_group().get_id() * itemID.get_local_range() + itemID.get_local_id()};
221
222 for (size_t p = 0; p < numP; p++) {
224 const size_t plane_input_offset = indexMapper.mapGpuInputPlaneToTensorInputOffset(p);
225 for (size_t k = itemID.get_local_id(2); k < num_input[2]; k += itemID.get_local_range()[2]) {
226 size_t local_index_dim2 = num_input[0] * num_input[1] * k;
227 bool cond_k_dim = (k + input_offset[2] < (input_range[2] + kernel_size[2] - 1));
228 for (size_t j = itemID.get_local_id(1); j < num_input[1]; j += itemID.get_local_range()[1]) {
229 bool cond_j_dim = cond_k_dim && (j + input_offset[1] < (input_range[1] + kernel_size[1] - 1));
230 size_t local_index_dim1 = (num_input[0] * j) + local_index_dim2;
231 for (size_t i = itemID.get_local_id(0); i < num_input[0]; i += itemID.get_local_range()[0]) {
232 bool conds = cond_j_dim && (i + input_offset[0] < (input_range[0] + kernel_size[0] - 1));
233 const size_t local_index = local_index_dim1 + i;
234 const size_t tensor_index =
235 plane_input_offset + indexMapper.mapGpuInputKernelToTensorInputOffset(
236 i + input_offset[0], j + input_offset[1], k + input_offset[2]);
237 local_acc[local_index] = conds ? device_evaluator.coeff(tensor_index) : CoeffReturnType(0);
238 }
239 }
240 }
241 itemID.barrier(cl::sycl::access::fence_space::local_space);
242
243 // calculate the convolution
244
245 if (boundary_check(itemID.get_global_id() < input_range)) {
246 CoeffReturnType result = static_cast<CoeffReturnType>(0);
247 for (size_t k = 0; k < kernel_size[2]; k++) {
248 for (size_t j = 0; j < kernel_size[1]; j++) {
249 for (size_t i = 0; i < kernel_size[0]; i++) {
250 const size_t kernel_index = i + kernel_size[0] * (j + kernel_size[1] * k);
251 const size_t local_index =
252 ((i + itemID.get_local_id(0)) +
253 num_input[0] * ((j + itemID.get_local_id(1)) + num_input[1] * (k + itemID.get_local_id(2))));
254
255 result += (local_acc[local_index] * kernel_ptr[kernel_index]);
256 }
257 }
258 }
259 const size_t tensor_index =
260 indexMapper.mapGpuOutputPlaneToTensorOutputOffset(p) +
261 indexMapper.mapGpuOutputKernelToTensorOutputOffset(output_offset[0], output_offset[1], output_offset[2]);
262 buffer_ptr[tensor_index] = result;
263 }
264
265 itemID.barrier(cl::sycl::access::fence_space::local_space);
266 }
267 }
268};
269
270template <typename Indices, typename InputArgType, typename KernelArgType>
271struct TensorEvaluator<const TensorConvolutionOp<Indices, InputArgType, KernelArgType>, Eigen::SyclDevice> {
272 typedef TensorConvolutionOp<Indices, InputArgType, KernelArgType> XprType;
273
274 static constexpr int NumDims =
275 internal::array_size<typename TensorEvaluator<InputArgType, Eigen::SyclDevice>::Dimensions>::value;
276 static constexpr int NumKernelDims = internal::array_size<Indices>::value;
277 typedef typename XprType::Index Index;
278 typedef DSizes<Index, NumDims> Dimensions;
279 typedef typename TensorEvaluator<KernelArgType, Eigen::SyclDevice>::Dimensions KernelDimensions;
280 typedef const Eigen::SyclDevice Device;
281 typedef typename XprType::CoeffReturnType CoeffReturnType;
282 typedef typename PacketType<CoeffReturnType, Eigen::SyclDevice>::type PacketReturnType;
283 typedef typename InputArgType::Scalar Scalar;
284 static constexpr int PacketSize = PacketType<CoeffReturnType, Device>::size;
285 typedef StorageMemory<CoeffReturnType, Eigen::SyclDevice> Storage;
286 typedef typename Storage::Type EvaluatorPointerType;
287 typedef StorageMemory<const CoeffReturnType, Eigen::SyclDevice> KernelStorage;
288
289 static constexpr int Layout = TensorEvaluator<InputArgType, Eigen::SyclDevice>::Layout;
290 enum {
291 IsAligned = TensorEvaluator<InputArgType, Eigen::SyclDevice>::IsAligned &
292 TensorEvaluator<KernelArgType, Eigen::SyclDevice>::IsAligned,
293 PacketAccess = false,
294 BlockAccess = false,
295 PreferBlockAccess = false,
296 CoordAccess = false, // to be implemented
297 RawAccess = false
298 };
299
300 //===- Tensor block evaluation strategy (see TensorBlock.h) -------------===//
301 typedef internal::TensorBlockNotImplemented TensorBlock;
302 //===--------------------------------------------------------------------===//
303
304 TensorEvaluator(const XprType &op, const Eigen::SyclDevice &device)
305 : m_inputImpl(op.inputExpression(), device),
306 m_kernelArg(op.kernelExpression()),
307 m_kernelImpl(op.kernelExpression(), device),
308 m_indices(op.indices()),
309 m_buf(nullptr),
310 m_kernel(nullptr),
311 m_local_kernel(false),
312 m_device(device) {
313 EIGEN_STATIC_ASSERT((static_cast<int>(TensorEvaluator<InputArgType, Eigen::SyclDevice>::Layout) ==
314 static_cast<int>(TensorEvaluator<KernelArgType, Eigen::SyclDevice>::Layout)),
315 YOU_MADE_A_PROGRAMMING_MISTAKE);
316
317 const typename TensorEvaluator<InputArgType, Eigen::SyclDevice>::Dimensions &input_dims = m_inputImpl.dimensions();
318 const typename TensorEvaluator<KernelArgType, Eigen::SyclDevice>::Dimensions &kernel_dims =
319 m_kernelImpl.dimensions();
320
321 m_dimensions = m_inputImpl.dimensions();
322 for (int i = 0; i < NumKernelDims; ++i) {
323 const Index index = op.indices()[i];
324 const Index input_dim = input_dims[index];
325 const Index kernel_dim = kernel_dims[i];
326 const Index result_dim = input_dim - kernel_dim + 1;
327 m_dimensions[index] = result_dim;
328 }
329 }
330
331 EIGEN_DEVICE_FUNC const Dimensions &dimensions() const { return m_dimensions; }
332
333 EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(EvaluatorPointerType data) {
334 preloadKernel();
335 m_inputImpl.evalSubExprsIfNeeded(nullptr);
336 if (data) {
337 executeEval(data);
338 return false;
339 } else {
340 m_buf = (EvaluatorPointerType)m_device.get(
341 (Scalar *)m_device.allocate_temp(dimensions().TotalSize() * sizeof(Scalar)));
342 executeEval(m_buf);
343 return true;
344 }
345 }
346
347 EIGEN_STRONG_INLINE void cleanup() {
348 m_inputImpl.cleanup();
349 if (m_buf) {
350 m_device.deallocate_temp(m_buf);
351 m_buf = nullptr;
352 }
353 if (m_local_kernel) {
354 m_device.deallocate_temp(m_kernel);
355 m_local_kernel = false;
356 }
357 m_kernel = nullptr;
358 }
360 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Device &device() const { return m_device; }
362 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EvaluatorPointerType data() const { return m_buf; }
363
364 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void preloadKernel() {
365 // Don't make a local copy of the kernel unless we have to (i.e. it's an
366 // expression that needs to be evaluated)
367 typename KernelStorage::Type in_place = m_kernelImpl.data();
368 if (in_place) {
369 m_kernel = in_place;
370 m_local_kernel = false;
371 } else {
372 ptrdiff_t kernel_sz = m_kernelImpl.dimensions().TotalSize() * sizeof(Scalar);
373 EvaluatorPointerType local = (EvaluatorPointerType)m_device.get((Scalar *)m_device.allocate_temp(kernel_sz));
374 typedef TensorEvalToOp<const KernelArgType> EvalTo;
375 EvalTo evalToTmp(m_device.get(local), m_kernelArg);
376 const bool PacketAccess = internal::IsVectorizable<Eigen::SyclDevice, KernelArgType>::value;
377 internal::TensorExecutor<const EvalTo, Eigen::SyclDevice, PacketAccess>::run(evalToTmp, m_device);
378 m_kernel = local;
379 m_local_kernel = true;
380 }
381 }
382
383 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void executeEval(EvaluatorPointerType data) const {
384 typedef TensorEvaluator<InputArgType, Eigen::SyclDevice> InputEvaluator;
385 typedef typename InputEvaluator::Dimensions InputDims;
386 switch (NumKernelDims) {
387 case 1: {
388 const size_t numX = dimensions()[m_indices[0]];
389 const size_t numP = dimensions().TotalSize() / numX;
390 const auto input_dim = std::array<size_t, 2>{numX, numP};
391 auto global_range = cl::sycl::range<2>{1, 1};
392 auto local_range = cl::sycl::range<2>{1, 1};
393 const size_t kernel_size = m_kernelImpl.dimensions().TotalSize();
394
395 m_device.parallel_for_setup(input_dim, global_range, local_range);
396 const size_t local_memory_size = (local_range[0] + kernel_size - 1) * (local_range[1]);
397 eigen_assert(static_cast<unsigned long>(local_memory_size) <= m_device.sharedMemPerBlock());
398 const array<Index, 1> indices{{m_indices[0]}};
399 const array<Index, 1> kernel_dims{{m_kernelImpl.dimensions()[0]}};
400 internal::IndexMapper<Index, InputDims, 1, Layout> indexMapper(m_inputImpl.dimensions(), kernel_dims, indices);
401
402 typedef EigenConvolutionKernel<InputEvaluator, CoeffReturnType, Scalar, Index, InputDims,
403 typename KernelStorage::Type, EvaluatorPointerType, convolution_type::CONV1D>
404 ConvKernel;
405
406 m_device
407 .template binary_kernel_launcher<CoeffReturnType, ConvKernel>(
408 m_inputImpl, m_kernel, data, cl::sycl::nd_range<2>(global_range, local_range), local_memory_size,
409 indexMapper, kernel_size, cl::sycl::range<2>(input_dim[0], input_dim[1]))
410 .wait();
411 break;
412 }
413
414 case 2: {
415 auto kernel_index = std::array<size_t, 2>{static_cast<int>(Layout) == static_cast<int>(ColMajor) ? 0 : 1,
416 static_cast<int>(Layout) == static_cast<int>(ColMajor) ? 1 : 0};
417 auto kernel_size = cl::sycl::range<2>{(size_t)m_kernelImpl.dimensions()[kernel_index[0]],
418 (size_t)m_kernelImpl.dimensions()[kernel_index[1]]};
419 const size_t numX = dimensions()[m_indices[kernel_index[0]]];
420 const size_t numY = dimensions()[m_indices[kernel_index[1]]];
421 const size_t numP = dimensions().TotalSize() / (numX * numY);
422 auto input_dim = std::array<size_t, 3>{numX, numY, numP};
423
424 auto global_range = cl::sycl::range<3>{1, 1, 1};
425 auto local_range = cl::sycl::range<3>{1, 1, 1};
426
427 m_device.parallel_for_setup(input_dim, global_range, local_range);
428
429 const size_t local_memory_size =
430 (local_range[0] + kernel_size[0] - 1) * (local_range[1] + kernel_size[1] - 1) * local_range[2];
431 eigen_assert(static_cast<unsigned long>(local_memory_size) <= m_device.sharedMemPerBlock());
432 const array<Index, 2> indices{{m_indices[kernel_index[0]], m_indices[kernel_index[1]]}};
433 const array<Index, 2> kernel_dims{
434 {m_kernelImpl.dimensions()[kernel_index[0]], m_kernelImpl.dimensions()[kernel_index[1]]}};
435 internal::IndexMapper<Index, InputDims, 2, Layout> indexMapper(m_inputImpl.dimensions(), kernel_dims, indices);
436 typedef EigenConvolutionKernel<InputEvaluator, CoeffReturnType, Scalar, Index, InputDims,
437 typename KernelStorage::Type, EvaluatorPointerType, convolution_type::CONV2D>
438 ConvKernel;
439 m_device
440 .template binary_kernel_launcher<CoeffReturnType, ConvKernel>(
441 m_inputImpl, m_kernel, data, cl::sycl::nd_range<3>(global_range, local_range), local_memory_size,
442 indexMapper, kernel_size, cl::sycl::range<3>{input_dim[0], input_dim[1], input_dim[2]})
443 .wait();
444 break;
445 }
446
447 case 3: {
448 auto kernel_index = std::array<size_t, 3>{static_cast<int>(Layout) == static_cast<int>(ColMajor) ? 0 : 2,
449 static_cast<int>(Layout) == static_cast<int>(ColMajor) ? 1 : 1,
450 static_cast<int>(Layout) == static_cast<int>(ColMajor) ? 2 : 0};
451
452 auto kernel_size = cl::sycl::range<3>{(size_t)m_kernelImpl.dimensions()[kernel_index[0]],
453 (size_t)m_kernelImpl.dimensions()[kernel_index[1]],
454 (size_t)m_kernelImpl.dimensions()[kernel_index[2]]};
455
456 const size_t numX = dimensions()[m_indices[kernel_index[0]]];
457 const size_t numY = dimensions()[m_indices[kernel_index[1]]];
458 const size_t numZ = dimensions()[m_indices[kernel_index[2]]];
459 auto input_dim = std::array<size_t, 3>{numX, numY, numZ};
460 const size_t numP = dimensions().TotalSize() / (numX * numY * numZ);
461
462 const array<Index, 3> indices{
463 {m_indices[kernel_index[0]], m_indices[kernel_index[1]], m_indices[kernel_index[2]]}};
464 const array<Index, 3> kernel_dims{{m_kernelImpl.dimensions()[kernel_index[0]],
465 m_kernelImpl.dimensions()[kernel_index[1]],
466 m_kernelImpl.dimensions()[kernel_index[2]]}};
467
468 internal::IndexMapper<Index, InputDims, 3, Layout> indexMapper(m_inputImpl.dimensions(), kernel_dims, indices);
469
470 auto global_range = cl::sycl::range<3>{1, 1, 1};
471 auto local_range = cl::sycl::range<3>{1, 1, 1};
472
473 m_device.parallel_for_setup(input_dim, global_range, local_range);
474 auto local_memory_range = (local_range + kernel_size - 1);
475 const size_t local_memory_size = local_memory_range[0] * local_memory_range[1] * local_memory_range[2];
476
477 eigen_assert(static_cast<unsigned long>(local_memory_size) <= m_device.sharedMemPerBlock());
478 typedef EigenConvolutionKernel<InputEvaluator, CoeffReturnType, Scalar, Index, InputDims,
479 typename KernelStorage::Type, EvaluatorPointerType, convolution_type::CONV3D>
480 ConvKernel;
481 m_device
482 .template binary_kernel_launcher<CoeffReturnType, ConvKernel>(
483 m_inputImpl, m_kernel, data, cl::sycl::nd_range<3>(global_range, local_range), local_memory_size,
484 indexMapper, kernel_size, cl::sycl::range<3>(input_dim[0], input_dim[1], input_dim[2]), numP)
485 .wait();
486 break;
487 }
488
489 default: {
490 EIGEN_STATIC_ASSERT((NumKernelDims >= 1 && NumKernelDims <= 3),
491 THIS_METHOD_IS_ONLY_FOR_OBJECTS_OF_A_SPECIFIC_SIZE);
492 }
493 }
494 }
495
496 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
497 eigen_assert(m_buf != nullptr);
498 eigen_assert(index < m_dimensions.TotalSize());
499 return m_buf[index];
500 }
501
502 template <int LoadMode>
503 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(const Index index) const {
504 eigen_assert(m_buf != nullptr);
505 eigen_assert(index < m_dimensions.TotalSize());
506 return internal::ploadt<PacketReturnType, LoadMode>(m_buf + index);
507 }
508
509 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const {
510 // TODO(rmlarsen): For now, this is just a copy of the CPU cost
511 // model.
512 const double kernel_size = m_kernelImpl.dimensions().TotalSize();
513 // We ignore the use of fused multiply-add.
514 const double convolve_compute_cost = TensorOpCost::AddCost<Scalar>() + TensorOpCost::MulCost<Scalar>();
515 const double firstIndex_compute_cost =
516 NumDims *
517 (2 * TensorOpCost::AddCost<Index>() + 2 * TensorOpCost::MulCost<Index>() + TensorOpCost::DivCost<Index>());
518 return TensorOpCost(0, 0, firstIndex_compute_cost, vectorized, PacketSize) +
519 kernel_size * (m_inputImpl.costPerCoeff(vectorized) + m_kernelImpl.costPerCoeff(vectorized) +
520 TensorOpCost(0, 0, convolve_compute_cost, vectorized, PacketSize));
521 }
522
523 private:
524 // No assignment (copies are needed by the kernels)
525 TensorEvaluator &operator=(const TensorEvaluator &) = delete;
526 TensorEvaluator<InputArgType, Eigen::SyclDevice> m_inputImpl;
527 KernelArgType m_kernelArg;
528 TensorEvaluator<KernelArgType, Eigen::SyclDevice> m_kernelImpl;
529 Indices m_indices;
530 Dimensions m_dimensions;
531 EvaluatorPointerType m_buf;
532 typename KernelStorage::Type m_kernel;
533 bool m_local_kernel;
534 const Eigen::SyclDevice EIGEN_DEVICE_REF m_device;
535};
536
537} // end namespace Eigen
538
539#endif // EIGEN_TENSOR_TENSOR_CONVOLUTION_SYCL_H
Definition TensorConvolution.h:223
Namespace containing all symbols from the Eigen library.
The tensor evaluator class.
Definition TensorEvaluator.h:47