2016-11-04 18:18:19 +00:00
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Mehdi Goli Codeplay Software Ltd.
// Ralph Potter Codeplay Software Ltd.
// Luke Iwanski Codeplay Software Ltd.
// Contact: <eigen@codeplay.com>
//
// 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/.
/*****************************************************************
* TensorSyclPlaceHolderExpr . h
*
* \ brief :
* This is the specialisation of the placeholder expression based on the
* operation type
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef UNSUPPORTED_EIGEN_CXX11_SRC_TENSOR_TENSOR_REDUCTION_SYCL_HPP
# define UNSUPPORTED_EIGEN_CXX11_SRC_TENSOR_TENSOR_REDUCTION_SYCL_HPP
namespace Eigen {
namespace internal {
2017-02-07 15:43:17 +00:00
template < typename OP , typename CoeffReturnType > struct syclGenericBufferReducer {
template < typename BufferTOut , typename BufferTIn >
2017-02-06 18:05:23 +00:00
static void run ( OP op , BufferTOut & bufOut , BufferTIn & bufI , const Eigen : : SyclDevice & dev , size_t length , size_t local ) {
2016-11-04 18:18:19 +00:00
do {
2017-02-06 18:05:23 +00:00
auto f = [ length , local , op , & bufOut , & bufI ] ( cl : : sycl : : handler & h ) mutable {
2016-11-04 18:18:19 +00:00
cl : : sycl : : nd_range < 1 > r { cl : : sycl : : range < 1 > { std : : max ( length , local ) } ,
cl : : sycl : : range < 1 > { std : : min ( length , local ) } } ;
/* Two accessors are used: one to the buffer that is being reduced,
* and a second to local memory , used to store intermediate data . */
2016-12-16 19:46:45 +00:00
auto aI = bufI . template get_access < cl : : sycl : : access : : mode : : read_write > ( h ) ;
auto aOut = bufOut . template get_access < cl : : sycl : : access : : mode : : discard_write > ( h ) ;
typedef decltype ( aI ) InputAccessor ;
typedef decltype ( aOut ) OutputAccessor ;
typedef cl : : sycl : : accessor < CoeffReturnType , 1 , cl : : sycl : : access : : mode : : read_write , cl : : sycl : : access : : target : : local > LocalAccessor ;
LocalAccessor scratch ( cl : : sycl : : range < 1 > ( local ) , h ) ;
2016-11-04 18:18:19 +00:00
/* The parallel_for invocation chosen is the variant with an nd_item
* parameter , since the code requires barriers for correctness . */
2017-02-06 18:05:23 +00:00
h . parallel_for ( r , TensorSycl : : internal : : GenericKernelReducer < CoeffReturnType , OP , OutputAccessor , InputAccessor , LocalAccessor > ( op , aOut , aI , scratch , length , local ) ) ;
2016-11-04 18:18:19 +00:00
} ;
2016-11-18 16:20:42 +00:00
dev . sycl_queue ( ) . submit ( f ) ;
2016-12-14 17:38:53 +00:00
dev . asynchronousExec ( ) ;
2016-11-04 18:18:19 +00:00
/* At this point, you could queue::wait_and_throw() to ensure that
* errors are caught quickly . However , this would likely impact
* performance negatively . */
length = length / local ;
} while ( length > 1 ) ;
2017-02-07 15:43:17 +00:00
}
2016-11-04 18:18:19 +00:00
2017-02-07 15:43:17 +00:00
} ;
2016-11-04 18:18:19 +00:00
2017-02-07 15:43:17 +00:00
template < typename CoeffReturnType > struct syclGenericBufferReducer < Eigen : : internal : : MeanReducer < CoeffReturnType > , CoeffReturnType > {
template < typename BufferTOut , typename BufferTIn >
static void run ( Eigen : : internal : : MeanReducer < CoeffReturnType > , BufferTOut & bufOut , BufferTIn & bufI , const Eigen : : SyclDevice & dev , size_t length , size_t local ) {
syclGenericBufferReducer < Eigen : : internal : : SumReducer < CoeffReturnType > , CoeffReturnType > : : run ( Eigen : : internal : : SumReducer < CoeffReturnType > ( ) ,
bufOut , bufI , dev , length , local ) ;
2016-11-04 18:18:19 +00:00
}
} ;
/// Self is useless here because in expression construction we are going to treat reduction as a leafnode.
/// we want to take reduction child and then build a construction and apply the full reducer function on it. Fullreducre applies the
/// reduction operation on the child of the reduction. once it is done the reduction is an empty shell and can be thrown away and treated as
// a leafNode.
2016-12-16 19:46:45 +00:00
2016-11-04 18:18:19 +00:00
template < typename Self , typename Op , bool Vectorizable >
struct FullReducer < Self , Op , const Eigen : : SyclDevice , Vectorizable > {
typedef typename Self : : CoeffReturnType CoeffReturnType ;
static const bool HasOptimizedImplementation = false ;
static void run ( const Self & self , Op & reducer , const Eigen : : SyclDevice & dev , CoeffReturnType * output ) {
typedef const typename Self : : ChildType HostExpr ; /// this is the child of reduction
2017-01-16 13:58:49 +00:00
typedef Eigen : : TensorSycl : : internal : : FunctorExtractor < TensorEvaluator < HostExpr , const Eigen : : SyclDevice > > FunctorExpr ;
2017-01-04 22:18:44 +00:00
FunctorExpr functors = TensorSycl : : internal : : extractFunctors ( self . impl ( ) ) ;
2016-11-04 18:18:19 +00:00
int red_factor = 256 ; /// initial reduction. If the size is less than red_factor we only creates one thread.
size_t inputSize = self . impl ( ) . dimensions ( ) . TotalSize ( ) ;
size_t rng = inputSize / red_factor ; // the total number of thread initially is half the size of the input
size_t remaining = inputSize % red_factor ;
if ( rng = = 0 ) {
red_factor = 1 ;
} ;
2016-11-18 16:20:42 +00:00
size_t tileSize = dev . sycl_queue ( ) . get_device ( ) . template get_info < cl : : sycl : : info : : device : : max_work_group_size > ( ) / 2 ;
2016-11-04 18:18:19 +00:00
size_t GRange = std : : max ( ( size_t ) 1 , rng ) ;
// convert global range to power of 2 for redecution
GRange - - ;
GRange | = GRange > > 1 ;
GRange | = GRange > > 2 ;
GRange | = GRange > > 4 ;
GRange | = GRange > > 8 ;
GRange | = GRange > > 16 ;
# if __x86_64__ || __ppc64__ || _WIN64
GRange | = GRange > > 32 ;
# endif
GRange + + ;
size_t outTileSize = tileSize ;
/// if the shared memory is less than the GRange, we set shared_mem size to the TotalSize and in this case one kernel would be created for recursion to reduce all to one.
if ( GRange < outTileSize ) outTileSize = GRange ;
/// creating the shared memory for calculating reduction.
/// This one is used to collect all the reduced value of shared memory as we dont have global barrier on GPU. Once it is saved we can
/// recursively apply reduction on it in order to reduce the whole.
auto temp_global_buffer = cl : : sycl : : buffer < CoeffReturnType , 1 > ( cl : : sycl : : range < 1 > ( GRange ) ) ;
typedef typename Eigen : : internal : : remove_all < decltype ( self . xprDims ( ) ) > : : type Dims ;
2016-12-16 19:46:45 +00:00
// Dims dims= self.xprDims();
//Op functor = reducer;
2016-11-18 16:20:42 +00:00
dev . sycl_queue ( ) . submit ( [ & ] ( cl : : sycl : : handler & cgh ) {
2017-01-19 11:30:59 +00:00
// this is a workaround for gcc 4.8 bug
2017-01-16 13:58:49 +00:00
typedef decltype ( TensorSycl : : internal : : createTupleOfAccessors ( cgh , self . impl ( ) ) ) TupleType ;
2016-11-04 18:18:19 +00:00
// create a tuple of accessors from Evaluator
2017-01-16 13:58:49 +00:00
TupleType tuple_of_accessors = TensorSycl : : internal : : createTupleOfAccessors ( cgh , self . impl ( ) ) ;
2016-11-04 18:18:19 +00:00
auto tmp_global_accessor = temp_global_buffer . template get_access < cl : : sycl : : access : : mode : : read_write , cl : : sycl : : access : : target : : global_buffer > ( cgh ) ;
2016-12-16 19:46:45 +00:00
typedef decltype ( tmp_global_accessor ) OutAccessor ;
cgh . parallel_for ( cl : : sycl : : nd_range < 1 > ( cl : : sycl : : range < 1 > ( GRange ) , cl : : sycl : : range < 1 > ( outTileSize ) ) ,
TensorSycl : : internal : : FullReductionKernelFunctor < CoeffReturnType , OutAccessor , HostExpr , FunctorExpr , Op , Dims , size_t , TupleType >
( tmp_global_accessor , rng , remaining , red_factor , reducer , self . xprDims ( ) , functors , tuple_of_accessors ) ) ;
2016-11-04 18:18:19 +00:00
} ) ;
2016-12-14 17:38:53 +00:00
dev . asynchronousExec ( ) ;
2016-11-04 18:18:19 +00:00
2016-12-16 19:46:45 +00:00
// getting final out buffer at the moment the created buffer is true because there is no need for assign
auto out_buffer = dev . get_sycl_buffer ( output ) ;
/// This is used to recursively reduce the tmp value to an element of 1;
2017-02-07 15:43:17 +00:00
syclGenericBufferReducer < Op , CoeffReturnType > : : run ( reducer , out_buffer , temp_global_buffer , dev , GRange , outTileSize ) ;
2016-11-04 18:18:19 +00:00
}
} ;
2016-11-25 16:19:07 +00:00
2016-11-04 18:18:19 +00:00
template < typename Self , typename Op >
struct InnerReducer < Self , Op , const Eigen : : SyclDevice > {
typedef typename Self : : CoeffReturnType CoeffReturnType ;
static const bool HasOptimizedImplementation = false ;
2017-02-07 15:43:17 +00:00
static bool run ( const Self & self , Op & reducer , const Eigen : : SyclDevice & dev , CoeffReturnType * output , typename Self : : Index num_values_to_reduce , typename Self : : Index num_coeffs_to_preserve ) {
2016-11-04 18:18:19 +00:00
typedef const typename Self : : ChildType HostExpr ; /// this is the child of reduction
2017-01-16 13:58:49 +00:00
typedef Eigen : : TensorSycl : : internal : : FunctorExtractor < TensorEvaluator < HostExpr , const Eigen : : SyclDevice > > FunctorExpr ;
2017-01-04 22:18:44 +00:00
FunctorExpr functors = TensorSycl : : internal : : extractFunctors ( self . impl ( ) ) ;
2016-11-23 16:30:41 +00:00
typename Self : : Index range , GRange , tileSize ;
2016-11-25 16:19:07 +00:00
typedef typename Eigen : : internal : : remove_all < decltype ( self . xprDims ( ) ) > : : type Dims ;
2016-11-04 18:18:19 +00:00
// getting final out buffer at the moment the created buffer is true because there is no need for assign
/// creating the shared memory for calculating reduction.
/// This one is used to collect all the reduced value of shared memory as we dont have global barrier on GPU. Once it is saved we can
/// recursively apply reduction on it in order to reduce the whole.
2016-11-25 16:19:07 +00:00
dev . parallel_for_setup ( num_coeffs_to_preserve , tileSize , range , GRange ) ;
2016-11-18 16:20:42 +00:00
dev . sycl_queue ( ) . submit ( [ & ] ( cl : : sycl : : handler & cgh ) {
2017-01-19 11:30:59 +00:00
// this is workaround for gcc 4.8 bug.
2017-01-16 13:58:49 +00:00
typedef decltype ( TensorSycl : : internal : : createTupleOfAccessors ( cgh , self . impl ( ) ) ) Tuple_of_Acc ;
2016-11-04 18:18:19 +00:00
// create a tuple of accessors from Evaluator
2017-01-16 13:58:49 +00:00
Tuple_of_Acc tuple_of_accessors = TensorSycl : : internal : : createTupleOfAccessors ( cgh , self . impl ( ) ) ;
2016-11-23 16:30:41 +00:00
auto output_accessor = dev . template get_sycl_accessor < cl : : sycl : : access : : mode : : discard_write > ( cgh , output ) ;
2017-02-07 15:43:17 +00:00
Index red_size = ( num_values_to_reduce ! = 0 ) ? num_values_to_reduce : static_cast < Index > ( 1 ) ;
2016-11-25 16:19:07 +00:00
cgh . parallel_for ( cl : : sycl : : nd_range < 1 > ( cl : : sycl : : range < 1 > ( GRange ) , cl : : sycl : : range < 1 > ( tileSize ) ) ,
2016-12-16 19:46:45 +00:00
TensorSycl : : internal : : ReductionFunctor < HostExpr , FunctorExpr , Tuple_of_Acc , Dims , Op , typename Self : : Index >
2017-02-07 15:43:17 +00:00
( output_accessor , functors , tuple_of_accessors , self . xprDims ( ) , reducer , range , red_size ) ) ;
2016-11-25 16:19:07 +00:00
2016-11-04 18:18:19 +00:00
} ) ;
2016-12-14 17:38:53 +00:00
dev . asynchronousExec ( ) ;
2016-11-04 18:18:19 +00:00
return false ;
}
} ;
} // end namespace internal
} // namespace Eigen
# endif // UNSUPPORTED_EIGEN_CXX11_SRC_TENSOR_TENSOR_REDUCTION_SYCL_HPP