// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2016 Benoit Steiner // Mehdi Goli Codeplay Software Ltd. // Ralph Potter Codeplay Software Ltd. // Luke Iwanski Codeplay Software Ltd. // Cummins Chris PhD student at The University of Edinburgh. // Contact: // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #if defined(EIGEN_USE_SYCL) && !defined(EIGEN_CXX11_TENSOR_TENSOR_DEVICE_SYCL_H) #define EIGEN_CXX11_TENSOR_TENSOR_DEVICE_SYCL_H namespace Eigen { /// \struct BufferT is used to specialise add_sycl_buffer function for // two types of buffer we have. When the MapAllocator is true, we create the // sycl buffer with MapAllocator. /// We have to const_cast the input pointer in order to work around the fact /// that sycl does not accept map allocator for const pointer. template struct BufferT { using Type = cl::sycl::buffer>; static inline void add_sycl_buffer( const T *ptr, size_t num_bytes, std::map> &buffer_map) { buffer_map.insert(std::pair>( ptr, std::shared_ptr(std::make_shared( Type(const_cast(ptr), cl::sycl::range<1>(num_bytes)))))); } }; /// specialisation of the \ref BufferT when the MapAllocator is false. In this /// case we only create the device-only buffer. template struct BufferT { using Type = cl::sycl::buffer; static inline void add_sycl_buffer( const T *ptr, size_t num_bytes, std::map> &buffer_map) { buffer_map.insert(std::pair>( ptr, std::shared_ptr( std::make_shared(Type(cl::sycl::range<1>(num_bytes)))))); } }; struct SyclDevice { /// class members /// sycl queue cl::sycl::queue &m_queue; /// std::map is the container used to make sure that we create only one buffer /// per pointer. The lifespan of the buffer /// now depends on the lifespan of SyclDevice. If a non-read-only pointer is /// needed to be accessed on the host we should manually deallocate it. mutable std::map> buffer_map; SyclDevice(cl::sycl::queue &q) : m_queue(q) {} // destructor ~SyclDevice() { deallocate_all(); } template void deallocate(const T *p) const { auto it = buffer_map.find(p); if (it != buffer_map.end()) { buffer_map.erase(it); } } void deallocate_all() const { buffer_map.clear(); } /// creation of sycl accessor for a buffer. This function first tries to find /// the buffer in the buffer_map. /// If found it gets the accessor from it, if not, the function then adds an /// entry by creating a sycl buffer /// for that particular pointer. template inline cl::sycl::accessor get_sycl_accessor(size_t num_bytes, cl::sycl::handler &cgh, const T *ptr) const { auto it = buffer_map.find(ptr); if (it == buffer_map.end()) { BufferT::add_sycl_buffer(ptr, num_bytes, buffer_map); } return ( ((typename BufferT::Type *)(buffer_map.at(ptr).get())) ->template get_access(cgh)); } /// allocating memory on the cpu EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void *allocate(size_t num_bytes) const { return internal::aligned_malloc(num_bytes); } // some runtime conditions that can be applied here bool isDeviceSuitable() const { return true; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void deallocate(void *buffer) const { internal::aligned_free(buffer); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpy(void *dst, const void *src, size_t n) const { ::memcpy(dst, src, n); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpyHostToDevice( void *dst, const void *src, size_t n) const { memcpy(dst, src, n); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpyDeviceToHost( void *dst, const void *src, size_t n) const { memcpy(dst, src, n); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memset(void *buffer, int c, size_t n) const { ::memset(buffer, c, n); } }; } // end namespace Eigen #endif // EIGEN_CXX11_TENSOR_TENSOR_DEVICE_SYCL_H