Eigen-Contrib  5.0.1
 
Loading...
Searching...
No Matches
TensorDeviceSycl.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#if defined(EIGEN_USE_SYCL) && !defined(EIGEN_TENSOR_TENSOR_DEVICE_SYCL_H)
17#define EIGEN_TENSOR_TENSOR_DEVICE_SYCL_H
18#include <unordered_set>
19
20// IWYU pragma: private
21#include "./InternalHeaderCheck.h"
22
23namespace Eigen {
24
25namespace TensorSycl {
26namespace internal {
27
29struct SyclDeviceInfo {
30 SyclDeviceInfo(cl::sycl::queue queue)
31 : local_mem_type(queue.get_device().template get_info<cl::sycl::info::device::local_mem_type>()),
32 max_work_item_sizes(queue.get_device().template get_info<cl::sycl::info::device::max_work_item_sizes<3>>()),
33 max_mem_alloc_size(queue.get_device().template get_info<cl::sycl::info::device::max_mem_alloc_size>()),
34 max_compute_units(queue.get_device().template get_info<cl::sycl::info::device::max_compute_units>()),
35 max_work_group_size(queue.get_device().template get_info<cl::sycl::info::device::max_work_group_size>()),
36 local_mem_size(queue.get_device().template get_info<cl::sycl::info::device::local_mem_size>()),
37 platform_name(queue.get_device().get_platform().template get_info<cl::sycl::info::platform::name>()),
38 device_name(queue.get_device().template get_info<cl::sycl::info::device::name>()),
39 device_vendor(queue.get_device().template get_info<cl::sycl::info::device::vendor>()) {}
40
41 cl::sycl::info::local_mem_type local_mem_type;
42 cl::sycl::id<3> max_work_item_sizes;
43 unsigned long max_mem_alloc_size;
44 unsigned long max_compute_units;
45 unsigned long max_work_group_size;
46 size_t local_mem_size;
47 std::string platform_name;
48 std::string device_name;
49 std::string device_vendor;
50};
51
52} // end namespace internal
53} // end namespace TensorSycl
54
55// All devices (even AMD CPU with intel OpenCL runtime) that support OpenCL and
56// can consume SPIR or SPIRV can use the Eigen SYCL backend and consequently
57// TensorFlow via the Eigen SYCL Backend.
58EIGEN_STRONG_INLINE auto get_sycl_supported_devices() -> decltype(cl::sycl::device::get_devices()) {
59#ifdef EIGEN_SYCL_USE_DEFAULT_SELECTOR
60 return {cl::sycl::device(cl::sycl::default_selector())};
61#else
62 std::vector<cl::sycl::device> supported_devices;
63 auto platform_list = cl::sycl::platform::get_platforms();
64 for (const auto &platform : platform_list) {
65 auto device_list = platform.get_devices();
66 auto platform_name = platform.template get_info<cl::sycl::info::platform::name>();
67 std::transform(platform_name.begin(), platform_name.end(), platform_name.begin(), ::tolower);
68 for (const auto &device : device_list) {
69 auto vendor = device.template get_info<cl::sycl::info::device::vendor>();
70 std::transform(vendor.begin(), vendor.end(), vendor.begin(), ::tolower);
71 bool unsupported_condition = (device.is_cpu() && platform_name.find("amd") != std::string::npos &&
72 vendor.find("apu") == std::string::npos) ||
73 (platform_name.find("experimental") != std::string::npos) || device.is_host();
74 if (!unsupported_condition) {
75 supported_devices.push_back(device);
76 }
77 }
78 }
79 return supported_devices;
80#endif
81}
82
83class QueueInterface {
84 public:
86 template <typename DeviceOrSelector>
87 explicit QueueInterface(const DeviceOrSelector &dev_or_sel, cl::sycl::async_handler handler,
88 unsigned num_threads = std::thread::hardware_concurrency())
89 : m_queue{dev_or_sel, handler, {sycl::property::queue::in_order()}},
90 m_thread_pool(num_threads),
91 m_device_info(m_queue) {}
92
93 template <typename DeviceOrSelector>
94 explicit QueueInterface(const DeviceOrSelector &dev_or_sel,
95 unsigned num_threads = std::thread::hardware_concurrency())
96 : QueueInterface(
97 dev_or_sel, [this](cl::sycl::exception_list l) { this->exception_caught_ = this->sycl_async_handler(l); },
98 num_threads) {}
99
100 explicit QueueInterface(const cl::sycl::queue &q, unsigned num_threads = std::thread::hardware_concurrency())
101 : m_queue(q), m_thread_pool(num_threads), m_device_info(m_queue) {}
102
103 EIGEN_STRONG_INLINE void *allocate(size_t num_bytes) const {
104#if EIGEN_MAX_ALIGN_BYTES > 0
105 return (void *)cl::sycl::aligned_alloc_device(EIGEN_MAX_ALIGN_BYTES, num_bytes, m_queue);
106#else
107 return (void *)cl::sycl::malloc_device(num_bytes, m_queue);
108#endif
109 }
110
111 EIGEN_STRONG_INLINE void *allocate_temp(size_t num_bytes) const {
112 return (void *)cl::sycl::malloc_device<uint8_t>(num_bytes, m_queue);
113 }
114
115 template <typename data_t>
116 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE data_t *get(data_t *data) const {
117 return data;
118 }
119
120 EIGEN_STRONG_INLINE void deallocate_temp(void *p) const { deallocate(p); }
121
122 EIGEN_STRONG_INLINE void deallocate_temp(const void *p) const { deallocate_temp(const_cast<void *>(p)); }
123
124 EIGEN_STRONG_INLINE void deallocate(void *p) const { cl::sycl::free(p, m_queue); }
125
130 EIGEN_STRONG_INLINE void memcpyHostToDevice(void *dst, const void *src, size_t n,
131 std::function<void()> callback) const {
132 auto e = m_queue.memcpy(dst, src, n);
133 synchronize_and_callback(e, callback);
134 }
135
140 EIGEN_STRONG_INLINE void memcpyDeviceToHost(void *dst, const void *src, size_t n,
141 std::function<void()> callback) const {
142 if (n == 0) {
143 if (callback) callback();
144 return;
145 }
146 auto e = m_queue.memcpy(dst, src, n);
147 synchronize_and_callback(e, callback);
148 }
149
153 EIGEN_STRONG_INLINE void memcpy(void *dst, const void *src, size_t n) const {
154 if (n == 0) {
155 return;
156 }
157 m_queue.memcpy(dst, src, n).wait();
158 }
159
163 EIGEN_STRONG_INLINE void memset(void *data, int c, size_t n) const {
164 if (n == 0) {
165 return;
166 }
167 m_queue.memset(data, c, n).wait();
168 }
169
170 template <typename T>
171 EIGEN_STRONG_INLINE void fill(T *begin, T *end, const T &value) const {
172 if (begin == end) {
173 return;
174 }
175 const size_t count = end - begin;
176 m_queue.fill(begin, value, count).wait();
177 }
178
179 template <typename OutScalar, typename sycl_kernel, typename Lhs, typename Rhs, typename OutPtr, typename Range,
180 typename Index, typename... T>
181 EIGEN_ALWAYS_INLINE cl::sycl::event binary_kernel_launcher(const Lhs &lhs, const Rhs &rhs, OutPtr outptr,
182 Range thread_range, Index scratchSize, T... var) const {
183 auto kernel_functor = [=](cl::sycl::handler &cgh) {
184 typedef cl::sycl::accessor<OutScalar, 1, cl::sycl::access::mode::read_write, cl::sycl::access::target::local>
185 LocalAccessor;
186
187 LocalAccessor scratch(cl::sycl::range<1>(scratchSize), cgh);
188 cgh.parallel_for(thread_range, sycl_kernel(scratch, lhs, rhs, outptr, var...));
189 };
190
191 return m_queue.submit(kernel_functor);
192 }
193
194 template <typename OutScalar, typename sycl_kernel, typename InPtr, typename OutPtr, typename Range, typename Index,
195 typename... T>
196 EIGEN_ALWAYS_INLINE cl::sycl::event unary_kernel_launcher(const InPtr &inptr, OutPtr &outptr, Range thread_range,
197 Index scratchSize, T... var) const {
198 auto kernel_functor = [=](cl::sycl::handler &cgh) {
199 typedef cl::sycl::accessor<OutScalar, 1, cl::sycl::access::mode::read_write, cl::sycl::access::target::local>
200 LocalAccessor;
201
202 LocalAccessor scratch(cl::sycl::range<1>(scratchSize), cgh);
203 cgh.parallel_for(thread_range, sycl_kernel(scratch, inptr, outptr, var...));
204 };
205 return m_queue.submit(kernel_functor);
206 }
207
208 template <typename OutScalar, typename sycl_kernel, typename InPtr, typename Range, typename Index, typename... T>
209 EIGEN_ALWAYS_INLINE cl::sycl::event nullary_kernel_launcher(const InPtr &inptr, Range thread_range, Index scratchSize,
210 T... var) const {
211 auto kernel_functor = [=](cl::sycl::handler &cgh) {
212 typedef cl::sycl::accessor<OutScalar, 1, cl::sycl::access::mode::read_write, cl::sycl::access::target::local>
213 LocalAccessor;
214
215 LocalAccessor scratch(cl::sycl::range<1>(scratchSize), cgh);
216 cgh.parallel_for(thread_range, sycl_kernel(scratch, inptr, var...));
217 };
218
219 return m_queue.submit(kernel_functor);
220 }
221
222 EIGEN_STRONG_INLINE void synchronize() const {
223#ifdef EIGEN_EXCEPTIONS
224 m_queue.wait_and_throw();
225#else
226 m_queue.wait();
227#endif
228 }
229
230 template <typename Index>
231 EIGEN_STRONG_INLINE void parallel_for_setup(Index n, Index &tileSize, Index &rng, Index &GRange) const {
232 tileSize = static_cast<Index>(getNearestPowerOfTwoWorkGroupSize());
233 tileSize = std::min(static_cast<Index>(EIGEN_SYCL_LOCAL_THREAD_DIM0 * EIGEN_SYCL_LOCAL_THREAD_DIM1),
234 static_cast<Index>(tileSize));
235 rng = n;
236 if (rng == 0) rng = static_cast<Index>(1);
237 GRange = rng;
238 if (tileSize > GRange)
239 tileSize = GRange;
240 else if (GRange > tileSize) {
241 Index xMode = static_cast<Index>(GRange % tileSize);
242 if (xMode != 0) GRange += static_cast<Index>(tileSize - xMode);
243 }
244 }
245
248 template <typename Index>
249 EIGEN_STRONG_INLINE void parallel_for_setup(const std::array<Index, 2> &input_dim, cl::sycl::range<2> &global_range,
250 cl::sycl::range<2> &local_range) const {
251 std::array<Index, 2> input_range = input_dim;
252 Index max_workgroup_Size = static_cast<Index>(getNearestPowerOfTwoWorkGroupSize());
253 max_workgroup_Size = std::min(static_cast<Index>(EIGEN_SYCL_LOCAL_THREAD_DIM0 * EIGEN_SYCL_LOCAL_THREAD_DIM1),
254 static_cast<Index>(max_workgroup_Size));
255 Index pow_of_2 = static_cast<Index>(std::log2(max_workgroup_Size));
256 local_range[1] = static_cast<Index>(std::pow(2, static_cast<Index>(pow_of_2 / 2)));
257 input_range[1] = input_dim[1];
258 if (input_range[1] == 0) input_range[1] = static_cast<Index>(1);
259 global_range[1] = input_range[1];
260 if (local_range[1] > global_range[1])
261 local_range[1] = global_range[1];
262 else if (global_range[1] > local_range[1]) {
263 Index xMode = static_cast<Index>(global_range[1] % local_range[1]);
264 if (xMode != 0) global_range[1] += static_cast<Index>(local_range[1] - xMode);
265 }
266 local_range[0] = static_cast<Index>(max_workgroup_Size / local_range[1]);
267 input_range[0] = input_dim[0];
268 if (input_range[0] == 0) input_range[0] = static_cast<Index>(1);
269 global_range[0] = input_range[0];
270 if (local_range[0] > global_range[0])
271 local_range[0] = global_range[0];
272 else if (global_range[0] > local_range[0]) {
273 Index xMode = static_cast<Index>(global_range[0] % local_range[0]);
274 if (xMode != 0) global_range[0] += static_cast<Index>(local_range[0] - xMode);
275 }
276 }
277
280 template <typename Index>
281 EIGEN_STRONG_INLINE void parallel_for_setup(const std::array<Index, 3> &input_dim, cl::sycl::range<3> &global_range,
282 cl::sycl::range<3> &local_range) const {
283 std::array<Index, 3> input_range = input_dim;
284 Index max_workgroup_Size = static_cast<Index>(getNearestPowerOfTwoWorkGroupSize());
285 max_workgroup_Size = std::min(static_cast<Index>(EIGEN_SYCL_LOCAL_THREAD_DIM0 * EIGEN_SYCL_LOCAL_THREAD_DIM1),
286 static_cast<Index>(max_workgroup_Size));
287 Index pow_of_2 = static_cast<Index>(std::log2(max_workgroup_Size));
288 local_range[2] = static_cast<Index>(std::pow(2, static_cast<Index>(pow_of_2 / 3)));
289 input_range[2] = input_dim[2];
290 if (input_range[2] == 0) input_range[1] = static_cast<Index>(1);
291 global_range[2] = input_range[2];
292 if (local_range[2] > global_range[2])
293 local_range[2] = global_range[2];
294 else if (global_range[2] > local_range[2]) {
295 Index xMode = static_cast<Index>(global_range[2] % local_range[2]);
296 if (xMode != 0) global_range[2] += static_cast<Index>(local_range[2] - xMode);
297 }
298 pow_of_2 = static_cast<Index>(std::log2(static_cast<Index>(max_workgroup_Size / local_range[2])));
299 local_range[1] = static_cast<Index>(std::pow(2, static_cast<Index>(pow_of_2 / 2)));
300 input_range[1] = input_dim[1];
301 if (input_range[1] == 0) input_range[1] = static_cast<Index>(1);
302 global_range[1] = input_range[1];
303 if (local_range[1] > global_range[1])
304 local_range[1] = global_range[1];
305 else if (global_range[1] > local_range[1]) {
306 Index xMode = static_cast<Index>(global_range[1] % local_range[1]);
307 if (xMode != 0) global_range[1] += static_cast<Index>(local_range[1] - xMode);
308 }
309 local_range[0] = static_cast<Index>(max_workgroup_Size / (local_range[1] * local_range[2]));
310 input_range[0] = input_dim[0];
311 if (input_range[0] == 0) input_range[0] = static_cast<Index>(1);
312 global_range[0] = input_range[0];
313 if (local_range[0] > global_range[0])
314 local_range[0] = global_range[0];
315 else if (global_range[0] > local_range[0]) {
316 Index xMode = static_cast<Index>(global_range[0] % local_range[0]);
317 if (xMode != 0) global_range[0] += static_cast<Index>(local_range[0] - xMode);
318 }
319 }
320
321 EIGEN_STRONG_INLINE bool has_local_memory() const {
322#if !defined(EIGEN_SYCL_LOCAL_MEM) && defined(EIGEN_SYCL_NO_LOCAL_MEM)
323 return false;
324#elif defined(EIGEN_SYCL_LOCAL_MEM) && !defined(EIGEN_SYCL_NO_LOCAL_MEM)
325 return true;
326#else
327 return m_device_info.local_mem_type == cl::sycl::info::local_mem_type::local;
328#endif
329 }
330
331 EIGEN_STRONG_INLINE unsigned long max_buffer_size() const { return m_device_info.max_mem_alloc_size; }
332
333 EIGEN_STRONG_INLINE unsigned long getNumSyclMultiProcessors() const { return m_device_info.max_compute_units; }
334
335 EIGEN_STRONG_INLINE unsigned long maxSyclThreadsPerBlock() const { return m_device_info.max_work_group_size; }
336
337 EIGEN_STRONG_INLINE cl::sycl::id<3> maxWorkItemSizes() const { return m_device_info.max_work_item_sizes; }
338
340 EIGEN_STRONG_INLINE int majorDeviceVersion() const { return 1; }
341
342 EIGEN_STRONG_INLINE unsigned long maxSyclThreadsPerMultiProcessor() const {
343 // OpenCL does not have such a concept
344 return 2;
345 }
346
347 EIGEN_STRONG_INLINE size_t sharedMemPerBlock() const { return m_device_info.local_mem_size; }
348
349 // This function returns the nearest power of 2 Work-group size which is <=
350 // maximum device workgroup size.
351 EIGEN_STRONG_INLINE size_t getNearestPowerOfTwoWorkGroupSize() const {
352 return getPowerOfTwo(m_device_info.max_work_group_size, false);
353 }
354
355 EIGEN_STRONG_INLINE std::string getPlatformName() const { return m_device_info.platform_name; }
356
357 EIGEN_STRONG_INLINE std::string getDeviceName() const { return m_device_info.device_name; }
358
359 EIGEN_STRONG_INLINE std::string getDeviceVendor() const { return m_device_info.device_vendor; }
360
361 // This function returns the nearest power of 2
362 // if roundup is true returns result>=wgsize
363 // else it returns result <= wgsize
364 EIGEN_STRONG_INLINE size_t getPowerOfTwo(size_t wGSize, bool roundUp) const {
365 if (roundUp) --wGSize;
366 wGSize |= (wGSize >> 1);
367 wGSize |= (wGSize >> 2);
368 wGSize |= (wGSize >> 4);
369 wGSize |= (wGSize >> 8);
370 wGSize |= (wGSize >> 16);
371#if EIGEN_ARCH_x86_64 || EIGEN_ARCH_ARM64 || EIGEN_OS_WIN64
372 wGSize |= (wGSize >> 32);
373#endif
374 return ((!roundUp) ? (wGSize - (wGSize >> 1)) : ++wGSize);
375 }
376
377 EIGEN_STRONG_INLINE cl::sycl::queue &sycl_queue() const { return m_queue; }
378
379 // This function checks if the runtime recorded an error for the
380 // underlying stream device.
381 EIGEN_STRONG_INLINE bool ok() const {
382 if (!exception_caught_) {
383 synchronize();
384 }
385 return !exception_caught_;
386 }
387
388 protected:
389 void synchronize_and_callback(cl::sycl::event e, const std::function<void()> &callback) const {
390 if (callback) {
391 auto callback_ = [=]() {
392#ifdef EIGEN_EXCEPTIONS
393 cl::sycl::event(e).wait_and_throw();
394#else
395 cl::sycl::event(e).wait();
396#endif
397 callback();
398 };
399 m_thread_pool.Schedule(std::move(callback_));
400 } else {
401#ifdef EIGEN_EXCEPTIONS
402 m_queue.wait_and_throw();
403#else
404 m_queue.wait();
405#endif
406 }
407 }
408
409 bool sycl_async_handler(cl::sycl::exception_list exceptions) const {
410 bool exception_caught = false;
411 for (const auto &e : exceptions) {
412 if (e) {
413 exception_caught = true;
414 EIGEN_THROW_X(e);
415 }
416 }
417 return exception_caught;
418 }
419
421 bool exception_caught_ = false;
423 mutable cl::sycl::queue m_queue;
426 mutable Eigen::ThreadPool m_thread_pool;
427
428 const TensorSycl::internal::SyclDeviceInfo m_device_info;
429};
430
431struct SyclDeviceBase {
434 const QueueInterface *m_queue_stream;
435 explicit SyclDeviceBase(const QueueInterface *queue_stream) : m_queue_stream(queue_stream) {}
436 EIGEN_STRONG_INLINE const QueueInterface *queue_stream() const { return m_queue_stream; }
437};
438
439// Here is a sycl device struct which accept the sycl queue interface
440// as an input
441struct SyclDevice : public SyclDeviceBase {
442 explicit SyclDevice(const QueueInterface *queue_stream) : SyclDeviceBase(queue_stream) {}
443
446 template <typename Index>
447 EIGEN_STRONG_INLINE void parallel_for_setup(Index n, Index &tileSize, Index &rng, Index &GRange) const {
448 queue_stream()->parallel_for_setup(n, tileSize, rng, GRange);
449 }
450
453 template <typename Index>
454 EIGEN_STRONG_INLINE void parallel_for_setup(const std::array<Index, 2> &input_dim, cl::sycl::range<2> &global_range,
455 cl::sycl::range<2> &local_range) const {
456 queue_stream()->parallel_for_setup(input_dim, global_range, local_range);
457 }
458
461 template <typename Index>
462 EIGEN_STRONG_INLINE void parallel_for_setup(const std::array<Index, 3> &input_dim, cl::sycl::range<3> &global_range,
463 cl::sycl::range<3> &local_range) const {
464 queue_stream()->parallel_for_setup(input_dim, global_range, local_range);
465 }
466
468 EIGEN_STRONG_INLINE void *allocate(size_t num_bytes) const { return queue_stream()->allocate(num_bytes); }
469
470 EIGEN_STRONG_INLINE void *allocate_temp(size_t num_bytes) const { return queue_stream()->allocate_temp(num_bytes); }
471
473 EIGEN_STRONG_INLINE void deallocate(void *p) const { queue_stream()->deallocate(p); }
474
475 EIGEN_STRONG_INLINE void deallocate_temp(void *buffer) const { queue_stream()->deallocate_temp(buffer); }
476
477 EIGEN_STRONG_INLINE void deallocate_temp(const void *buffer) const { queue_stream()->deallocate_temp(buffer); }
478
479 template <typename data_t>
480 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE data_t *get(data_t *data) const {
481 return data;
482 }
483
484 // some runtime conditions that can be applied here
485 EIGEN_STRONG_INLINE bool isDeviceSuitable() const { return true; }
486
488 template <typename Index>
489 EIGEN_STRONG_INLINE void memcpyHostToDevice(Index *dst, const Index *src, size_t n,
490 std::function<void()> callback = {}) const {
491 queue_stream()->memcpyHostToDevice(dst, src, n, callback);
492 }
494 template <typename Index>
495 EIGEN_STRONG_INLINE void memcpyDeviceToHost(void *dst, const Index *src, size_t n,
496 std::function<void()> callback = {}) const {
497 queue_stream()->memcpyDeviceToHost(dst, src, n, callback);
498 }
500 template <typename Index>
501 EIGEN_STRONG_INLINE void memcpy(void *dst, const Index *src, size_t n) const {
502 queue_stream()->memcpy(dst, src, n);
503 }
505 EIGEN_STRONG_INLINE void memset(void *data, int c, size_t n) const { queue_stream()->memset(data, c, n); }
507 template <typename T>
508 EIGEN_STRONG_INLINE void fill(T *begin, T *end, const T &value) const {
509 queue_stream()->fill(begin, end, value);
510 }
512 EIGEN_STRONG_INLINE cl::sycl::queue &sycl_queue() const { return queue_stream()->sycl_queue(); }
513
514 EIGEN_STRONG_INLINE size_t firstLevelCacheSize() const { return 48 * 1024; }
515
516 EIGEN_STRONG_INLINE size_t lastLevelCacheSize() const {
517 // We won't try to take advantage of the l2 cache for the time being, and
518 // there is no l3 cache on sycl devices.
519 return firstLevelCacheSize();
520 }
521 EIGEN_STRONG_INLINE unsigned long getNumSyclMultiProcessors() const {
522 return queue_stream()->getNumSyclMultiProcessors();
523 }
524 EIGEN_STRONG_INLINE unsigned long maxSyclThreadsPerBlock() const { return queue_stream()->maxSyclThreadsPerBlock(); }
525 EIGEN_STRONG_INLINE cl::sycl::id<3> maxWorkItemSizes() const { return queue_stream()->maxWorkItemSizes(); }
526 EIGEN_STRONG_INLINE unsigned long maxSyclThreadsPerMultiProcessor() const {
527 // OpenCL does not have such a concept
528 return queue_stream()->maxSyclThreadsPerMultiProcessor();
529 }
530 EIGEN_STRONG_INLINE size_t sharedMemPerBlock() const { return queue_stream()->sharedMemPerBlock(); }
531 EIGEN_STRONG_INLINE size_t getNearestPowerOfTwoWorkGroupSize() const {
532 return queue_stream()->getNearestPowerOfTwoWorkGroupSize();
533 }
534
535 EIGEN_STRONG_INLINE size_t getPowerOfTwo(size_t val, bool roundUp) const {
536 return queue_stream()->getPowerOfTwo(val, roundUp);
537 }
539 EIGEN_STRONG_INLINE int majorDeviceVersion() const { return queue_stream()->majorDeviceVersion(); }
540
541 EIGEN_STRONG_INLINE void synchronize() const { queue_stream()->synchronize(); }
542
543 // This function checks if the runtime recorded an error for the
544 // underlying stream device.
545 EIGEN_STRONG_INLINE bool ok() const { return queue_stream()->ok(); }
546
547 EIGEN_STRONG_INLINE bool has_local_memory() const { return queue_stream()->has_local_memory(); }
548 EIGEN_STRONG_INLINE long max_buffer_size() const { return queue_stream()->max_buffer_size(); }
549 EIGEN_STRONG_INLINE std::string getPlatformName() const { return queue_stream()->getPlatformName(); }
550 EIGEN_STRONG_INLINE std::string getDeviceName() const { return queue_stream()->getDeviceName(); }
551 EIGEN_STRONG_INLINE std::string getDeviceVendor() const { return queue_stream()->getDeviceVendor(); }
552 template <typename OutScalar, typename KernelType, typename... T>
553 EIGEN_ALWAYS_INLINE cl::sycl::event binary_kernel_launcher(T... var) const {
554 return queue_stream()->template binary_kernel_launcher<OutScalar, KernelType>(var...);
555 }
556 template <typename OutScalar, typename KernelType, typename... T>
557 EIGEN_ALWAYS_INLINE cl::sycl::event unary_kernel_launcher(T... var) const {
558 return queue_stream()->template unary_kernel_launcher<OutScalar, KernelType>(var...);
559 }
560
561 template <typename OutScalar, typename KernelType, typename... T>
562 EIGEN_ALWAYS_INLINE cl::sycl::event nullary_kernel_launcher(T... var) const {
563 return queue_stream()->template nullary_kernel_launcher<OutScalar, KernelType>(var...);
564 }
565};
566} // end namespace Eigen
567
568#endif // EIGEN_TENSOR_TENSOR_DEVICE_SYCL_H
Namespace containing all symbols from the Eigen library.