1533 lines
43 KiB
C++
1533 lines
43 KiB
C++
/*
|
|
//@HEADER
|
|
// ************************************************************************
|
|
//
|
|
// Kokkos v. 2.0
|
|
// Copyright (2014) Sandia Corporation
|
|
//
|
|
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
|
// the U.S. Government retains certain rights in this software.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// 1. Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// 2. Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// 3. Neither the name of the Corporation nor the names of the
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
|
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// Questions? Contact H. Carter Edwards (hcedwar@sandia.gov)
|
|
//
|
|
// ************************************************************************
|
|
//@HEADER
|
|
*/
|
|
|
|
#include <Kokkos_Core.hpp>
|
|
|
|
namespace TestAtomicViews {
|
|
|
|
//-------------------------------------------------
|
|
//-----------atomic view api tests-----------------
|
|
//-------------------------------------------------
|
|
|
|
template< class T , class ... P >
|
|
size_t allocation_count( const Kokkos::View<T,P...> & view )
|
|
{
|
|
const size_t card = view.size();
|
|
const size_t alloc = view.span();
|
|
|
|
const int memory_span = Kokkos::View<int*>::required_allocation_size(100);
|
|
|
|
return (card <= alloc && memory_span == 400) ? alloc : 0 ;
|
|
}
|
|
|
|
template< class DataType ,
|
|
class DeviceType ,
|
|
unsigned Rank = Kokkos::ViewTraits< DataType >::rank >
|
|
struct TestViewOperator_LeftAndRight ;
|
|
|
|
template< class DataType , class DeviceType >
|
|
struct TestViewOperator_LeftAndRight< DataType , DeviceType , 1 >
|
|
{
|
|
typedef typename DeviceType::execution_space execution_space ;
|
|
typedef typename DeviceType::memory_space memory_space ;
|
|
typedef typename execution_space::size_type size_type ;
|
|
|
|
typedef int value_type ;
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
static void join( volatile value_type & update ,
|
|
const volatile value_type & input )
|
|
{ update |= input ; }
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
static void init( value_type & update )
|
|
{ update = 0 ; }
|
|
|
|
|
|
typedef Kokkos::
|
|
View< DataType, Kokkos::LayoutLeft, execution_space, Kokkos::MemoryTraits< Kokkos::Atomic > > left_view ;
|
|
|
|
typedef Kokkos::
|
|
View< DataType, Kokkos::LayoutRight, execution_space, Kokkos::MemoryTraits< Kokkos::Atomic > > right_view ;
|
|
|
|
typedef Kokkos::
|
|
View< DataType, Kokkos::LayoutStride, execution_space, Kokkos::MemoryTraits< Kokkos::Atomic >> stride_view ;
|
|
|
|
left_view left ;
|
|
right_view right ;
|
|
stride_view left_stride ;
|
|
stride_view right_stride ;
|
|
long left_alloc ;
|
|
long right_alloc ;
|
|
|
|
TestViewOperator_LeftAndRight()
|
|
: left( "left" )
|
|
, right( "right" )
|
|
, left_stride( left )
|
|
, right_stride( right )
|
|
, left_alloc( allocation_count( left ) )
|
|
, right_alloc( allocation_count( right ) )
|
|
{}
|
|
|
|
static void testit()
|
|
{
|
|
TestViewOperator_LeftAndRight driver ;
|
|
|
|
int error_flag = 0 ;
|
|
|
|
Kokkos::parallel_reduce( 1 , driver , error_flag );
|
|
|
|
ASSERT_EQ( error_flag , 0 );
|
|
}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()( const size_type , value_type & update ) const
|
|
{
|
|
for ( unsigned i0 = 0 ; i0 < unsigned(left.dimension_0()) ; ++i0 )
|
|
{
|
|
// below checks that values match, but unable to check the references
|
|
// - should this be able to be checked?
|
|
if ( left(i0) != left(i0,0,0,0,0,0,0,0) ) { update |= 3 ; }
|
|
if ( right(i0) != right(i0,0,0,0,0,0,0,0) ) { update |= 3 ; }
|
|
if ( left(i0) != left_stride(i0) ) { update |= 4 ; }
|
|
if ( right(i0) != right_stride(i0) ) { update |= 8 ; }
|
|
/*
|
|
if ( & left(i0) != & left(i0,0,0,0,0,0,0,0) ) { update |= 3 ; }
|
|
if ( & right(i0) != & right(i0,0,0,0,0,0,0,0) ) { update |= 3 ; }
|
|
if ( & left(i0) != & left_stride(i0) ) { update |= 4 ; }
|
|
if ( & right(i0) != & right_stride(i0) ) { update |= 8 ; }
|
|
*/
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
template< typename T, class DeviceType >
|
|
class TestAtomicViewAPI
|
|
{
|
|
public:
|
|
typedef DeviceType device ;
|
|
|
|
enum { N0 = 1000 ,
|
|
N1 = 3 ,
|
|
N2 = 5 ,
|
|
N3 = 7 };
|
|
|
|
typedef Kokkos::View< T , device > dView0 ;
|
|
typedef Kokkos::View< T* , device > dView1 ;
|
|
typedef Kokkos::View< T*[N1] , device > dView2 ;
|
|
typedef Kokkos::View< T*[N1][N2] , device > dView3 ;
|
|
typedef Kokkos::View< T*[N1][N2][N3] , device > dView4 ;
|
|
typedef Kokkos::View< const T*[N1][N2][N3] , device > const_dView4 ;
|
|
typedef Kokkos::View< T****, device, Kokkos::MemoryUnmanaged > dView4_unmanaged ;
|
|
typedef typename dView0::host_mirror_space host ;
|
|
|
|
typedef Kokkos::View< T , device , Kokkos::MemoryTraits< Kokkos::Atomic > > aView0 ;
|
|
typedef Kokkos::View< T* , device , Kokkos::MemoryTraits< Kokkos::Atomic > > aView1 ;
|
|
typedef Kokkos::View< T*[N1] , device , Kokkos::MemoryTraits< Kokkos::Atomic > > aView2 ;
|
|
typedef Kokkos::View< T*[N1][N2] , device , Kokkos::MemoryTraits< Kokkos::Atomic > > aView3 ;
|
|
typedef Kokkos::View< T*[N1][N2][N3] , device , Kokkos::MemoryTraits< Kokkos::Atomic > > aView4 ;
|
|
typedef Kokkos::View< const T*[N1][N2][N3] , device , Kokkos::MemoryTraits< Kokkos::Atomic > > const_aView4 ;
|
|
|
|
typedef Kokkos::View< T****, device, Kokkos::MemoryTraits< Kokkos::Unmanaged | Kokkos::Atomic > > aView4_unmanaged ;
|
|
|
|
typedef typename aView0::host_mirror_space host_atomic ;
|
|
|
|
TestAtomicViewAPI()
|
|
{
|
|
TestViewOperator_LeftAndRight< int[2] , device >::testit();
|
|
run_test_rank0();
|
|
run_test_rank4();
|
|
run_test_const();
|
|
}
|
|
|
|
|
|
static void run_test_rank0()
|
|
{
|
|
dView0 dx , dy ;
|
|
aView0 ax , ay , az ;
|
|
|
|
dx = dView0( "dx" );
|
|
dy = dView0( "dy" );
|
|
ASSERT_EQ( dx.use_count() , size_t(1) );
|
|
ASSERT_EQ( dy.use_count() , size_t(1) );
|
|
|
|
ax = dx ;
|
|
ay = dy ;
|
|
ASSERT_EQ( dx.use_count() , size_t(2) );
|
|
ASSERT_EQ( dy.use_count() , size_t(2) );
|
|
ASSERT_EQ( dx.use_count() , ax.use_count() );
|
|
|
|
az = ax ;
|
|
ASSERT_EQ( dx.use_count() , size_t(3) );
|
|
ASSERT_EQ( ax.use_count() , size_t(3) );
|
|
ASSERT_EQ( az.use_count() , size_t(3) );
|
|
ASSERT_EQ( az.use_count() , ax.use_count() );
|
|
}
|
|
|
|
static void run_test_rank4()
|
|
{
|
|
dView4 dx , dy ;
|
|
aView4 ax , ay , az ;
|
|
|
|
dx = dView4( "dx" , N0 );
|
|
dy = dView4( "dy" , N0 );
|
|
ASSERT_EQ( dx.use_count() , size_t(1) );
|
|
ASSERT_EQ( dy.use_count() , size_t(1) );
|
|
|
|
ax = dx ;
|
|
ay = dy ;
|
|
ASSERT_EQ( dx.use_count() , size_t(2) );
|
|
ASSERT_EQ( dy.use_count() , size_t(2) );
|
|
ASSERT_EQ( dx.use_count() , ax.use_count() );
|
|
|
|
dView4_unmanaged unmanaged_dx = dx;
|
|
ASSERT_EQ( dx.use_count() , size_t(2) );
|
|
|
|
az = ax ;
|
|
ASSERT_EQ( dx.use_count() , size_t(3) );
|
|
ASSERT_EQ( ax.use_count() , size_t(3) );
|
|
ASSERT_EQ( az.use_count() , size_t(3) );
|
|
ASSERT_EQ( az.use_count() , ax.use_count() );
|
|
|
|
aView4_unmanaged unmanaged_ax = ax;
|
|
ASSERT_EQ( ax.use_count() , size_t(3) );
|
|
|
|
aView4_unmanaged unmanaged_ax_from_ptr_dx = aView4_unmanaged(dx.data(),
|
|
dx.dimension_0(),
|
|
dx.dimension_1(),
|
|
dx.dimension_2(),
|
|
dx.dimension_3());
|
|
ASSERT_EQ( ax.use_count() , size_t(3) );
|
|
|
|
const_aView4 const_ax = ax ;
|
|
ASSERT_EQ( ax.use_count() , size_t(4) );
|
|
ASSERT_EQ( const_ax.use_count() , ax.use_count() );
|
|
|
|
ASSERT_FALSE( ax.data() == 0 );
|
|
ASSERT_FALSE( const_ax.data() == 0 ); // referenceable ptr
|
|
ASSERT_FALSE( unmanaged_ax.data() == 0 );
|
|
ASSERT_FALSE( unmanaged_ax_from_ptr_dx.data() == 0 );
|
|
ASSERT_FALSE( ay.data() == 0 );
|
|
// ASSERT_NE( ax , ay );
|
|
// Above test results in following runtime error from gtest:
|
|
// Expected: (ax) != (ay), actual: 32-byte object <30-01 D0-A0 D8-7F 00-00 00-31 44-0C 01-00 00-00 E8-03 00-00 00-00 00-00 69-00 00-00 00-00 00-00> vs 32-byte object <80-01 D0-A0 D8-7F 00-00 00-A1 4A-0C 01-00 00-00 E8-03 00-00 00-00 00-00 69-00 00-00 00-00 00-00>
|
|
|
|
ASSERT_EQ( ax.dimension_0() , unsigned(N0) );
|
|
ASSERT_EQ( ax.dimension_1() , unsigned(N1) );
|
|
ASSERT_EQ( ax.dimension_2() , unsigned(N2) );
|
|
ASSERT_EQ( ax.dimension_3() , unsigned(N3) );
|
|
|
|
ASSERT_EQ( ay.dimension_0() , unsigned(N0) );
|
|
ASSERT_EQ( ay.dimension_1() , unsigned(N1) );
|
|
ASSERT_EQ( ay.dimension_2() , unsigned(N2) );
|
|
ASSERT_EQ( ay.dimension_3() , unsigned(N3) );
|
|
|
|
ASSERT_EQ( unmanaged_ax_from_ptr_dx.capacity(),unsigned(N0)*unsigned(N1)*unsigned(N2)*unsigned(N3) );
|
|
}
|
|
|
|
typedef T DataType[2] ;
|
|
|
|
static void
|
|
check_auto_conversion_to_const(
|
|
const Kokkos::View< const DataType , device , Kokkos::MemoryTraits< Kokkos::Atomic> > & arg_const ,
|
|
const Kokkos::View< const DataType , device , Kokkos::MemoryTraits< Kokkos::Atomic> > & arg )
|
|
{
|
|
ASSERT_TRUE( arg_const == arg );
|
|
}
|
|
|
|
static void run_test_const()
|
|
{
|
|
typedef Kokkos::View< DataType , device , Kokkos::MemoryTraits< Kokkos::Atomic> > typeX ;
|
|
typedef Kokkos::View< const DataType , device , Kokkos::MemoryTraits< Kokkos::Atomic> > const_typeX ;
|
|
|
|
typeX x( "X" );
|
|
const_typeX xc = x ;
|
|
|
|
//ASSERT_TRUE( xc == x ); // const xc is referenceable, non-const x is not
|
|
//ASSERT_TRUE( x == xc );
|
|
|
|
check_auto_conversion_to_const( x , xc );
|
|
}
|
|
|
|
};
|
|
|
|
|
|
//---------------------------------------------------
|
|
//-----------initialization functors-----------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct InitFunctor_Seq {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
|
|
view_type input ;
|
|
const long length ;
|
|
|
|
InitFunctor_Seq( view_type & input_ , const long length_ )
|
|
: input(input_)
|
|
, length(length_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()( const long i ) const {
|
|
if ( i < length ) {
|
|
input(i) = (T) i ;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
struct InitFunctor_ModTimes {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
|
|
view_type input ;
|
|
const long length ;
|
|
const long remainder ;
|
|
|
|
InitFunctor_ModTimes( view_type & input_ , const long length_ , const long remainder_ )
|
|
: input(input_)
|
|
, length(length_)
|
|
, remainder(remainder_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()( const long i ) const {
|
|
if ( i < length ) {
|
|
if ( i % (remainder+1) == remainder ) {
|
|
input(i) = (T)2 ;
|
|
}
|
|
else {
|
|
input(i) = (T)1 ;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
struct InitFunctor_ModShift {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
|
|
view_type input ;
|
|
const long length ;
|
|
const long remainder ;
|
|
|
|
InitFunctor_ModShift( view_type & input_ , const long length_ , const long remainder_ )
|
|
: input(input_)
|
|
, length(length_)
|
|
, remainder(remainder_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()( const long i ) const {
|
|
if ( i < length ) {
|
|
if ( i % (remainder+1) == remainder ) {
|
|
input(i) = 1 ;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
//---------------------------------------------------
|
|
//-----------atomic view plus-equal------------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct PlusEqualAtomicViewFunctor {
|
|
|
|
typedef Kokkos::View< T* , execution_space , Kokkos::MemoryTraits< Kokkos::Atomic > > atomic_view_type ;
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
|
|
view_type input;
|
|
atomic_view_type even_odd_result;
|
|
const long length;
|
|
|
|
// Wrap the result view in an atomic view, use this for operator
|
|
PlusEqualAtomicViewFunctor( const view_type & input_ , view_type & even_odd_result_ , const long length_)
|
|
: input(input_)
|
|
, even_odd_result(even_odd_result_)
|
|
, length(length_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const long i) const {
|
|
if ( i < length ) {
|
|
if ( i % 2 == 0 ) {
|
|
even_odd_result(0) += input(i);
|
|
}
|
|
else {
|
|
even_odd_result(1) += input(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
T PlusEqualAtomicView(const long input_length) {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef typename view_type::HostMirror host_view_type ;
|
|
|
|
const long length = input_length;
|
|
|
|
view_type input("input_view",length) ;
|
|
view_type result_view("result_view",2) ;
|
|
|
|
InitFunctor_Seq<T, execution_space> init_f( input , length ) ;
|
|
Kokkos::parallel_for(Kokkos::RangePolicy<execution_space>(0, length) , init_f );
|
|
|
|
PlusEqualAtomicViewFunctor<T,execution_space> functor(input, result_view, length);
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), functor);
|
|
Kokkos::fence();
|
|
|
|
host_view_type h_result_view = Kokkos::create_mirror_view(result_view);
|
|
Kokkos::deep_copy(h_result_view, result_view);
|
|
|
|
return (T) (h_result_view(0) + h_result_view(1) ) ;
|
|
}
|
|
|
|
template<class T>
|
|
T PlusEqualAtomicViewCheck( const long input_length ) {
|
|
|
|
const long N = input_length;
|
|
T result[2];
|
|
if ( N % 2 == 0 ) {
|
|
const long half_sum_end = (N/2) - 1;
|
|
const long full_sum_end = N - 1;
|
|
result[0] = half_sum_end*(half_sum_end + 1)/2 ; //even sum
|
|
result[1] = ( full_sum_end*(full_sum_end + 1)/2 ) - result[0] ; // odd sum
|
|
}
|
|
else {
|
|
const long half_sum_end = (T)(N/2) ;
|
|
const long full_sum_end = N - 2;
|
|
result[0] = half_sum_end*(half_sum_end - 1)/2 ; //even sum
|
|
result[1] = ( full_sum_end*(full_sum_end - 1)/2 ) - result[0] ; // odd sum
|
|
}
|
|
|
|
return (T)(result[0] + result[1]);
|
|
}
|
|
|
|
template<class T,class DeviceType>
|
|
bool PlusEqualAtomicViewTest(long input_length)
|
|
{
|
|
T res = PlusEqualAtomicView<T,DeviceType>(input_length);
|
|
T resSerial = PlusEqualAtomicViewCheck<T>(input_length);
|
|
|
|
bool passed = true;
|
|
|
|
if ( resSerial != res ) {
|
|
passed = false;
|
|
|
|
std::cout << "Loop<"
|
|
<< typeid(T).name()
|
|
<< ">( test = PlusEqualAtomicViewTest"
|
|
<< " FAILED : "
|
|
<< resSerial << " != " << res
|
|
<< std::endl ;
|
|
}
|
|
|
|
return passed ;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------
|
|
//-----------atomic view minus-equal-----------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct MinusEqualAtomicViewFunctor {
|
|
|
|
typedef Kokkos::View< T* , execution_space , Kokkos::MemoryTraits< Kokkos::Atomic > > atomic_view_type ;
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
|
|
view_type input;
|
|
atomic_view_type even_odd_result;
|
|
const long length;
|
|
|
|
// Wrap the result view in an atomic view, use this for operator
|
|
MinusEqualAtomicViewFunctor( const view_type & input_ , view_type & even_odd_result_ , const long length_)
|
|
: input(input_)
|
|
, even_odd_result(even_odd_result_)
|
|
, length(length_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const long i) const {
|
|
if ( i < length ) {
|
|
if ( i % 2 == 0 ) {
|
|
even_odd_result(0) -= input(i);
|
|
}
|
|
else {
|
|
even_odd_result(1) -= input(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
T MinusEqualAtomicView(const long input_length) {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef typename view_type::HostMirror host_view_type ;
|
|
|
|
const long length = input_length;
|
|
|
|
view_type input("input_view",length) ;
|
|
view_type result_view("result_view",2) ;
|
|
|
|
InitFunctor_Seq<T, execution_space> init_f( input , length ) ;
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), init_f );
|
|
|
|
MinusEqualAtomicViewFunctor<T,execution_space> functor(input, result_view,length);
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), functor);
|
|
Kokkos::fence();
|
|
|
|
host_view_type h_result_view = Kokkos::create_mirror_view(result_view);
|
|
Kokkos::deep_copy(h_result_view, result_view);
|
|
|
|
return (T) (h_result_view(0) + h_result_view(1) ) ;
|
|
}
|
|
|
|
template<class T>
|
|
T MinusEqualAtomicViewCheck( const long input_length ) {
|
|
|
|
const long N = input_length;
|
|
T result[2];
|
|
if ( N % 2 == 0 ) {
|
|
const long half_sum_end = (N/2) - 1;
|
|
const long full_sum_end = N - 1;
|
|
result[0] = -1*( half_sum_end*(half_sum_end + 1)/2 ) ; //even sum
|
|
result[1] = -1*( ( full_sum_end*(full_sum_end + 1)/2 ) + result[0] ) ; // odd sum
|
|
}
|
|
else {
|
|
const long half_sum_end = (long)(N/2) ;
|
|
const long full_sum_end = N - 2;
|
|
result[0] = -1*( half_sum_end*(half_sum_end - 1)/2 ) ; //even sum
|
|
result[1] = -1*( ( full_sum_end*(full_sum_end - 1)/2 ) + result[0] ) ; // odd sum
|
|
}
|
|
|
|
return (result[0] + result[1]);
|
|
}
|
|
|
|
template<class T,class DeviceType>
|
|
bool MinusEqualAtomicViewTest(long input_length)
|
|
{
|
|
T res = MinusEqualAtomicView<T,DeviceType>(input_length);
|
|
T resSerial = MinusEqualAtomicViewCheck<T>(input_length);
|
|
|
|
bool passed = true;
|
|
|
|
if ( resSerial != res ) {
|
|
passed = false;
|
|
|
|
std::cout << "Loop<"
|
|
<< typeid(T).name()
|
|
<< ">( test = MinusEqualAtomicViewTest"
|
|
<< " FAILED : "
|
|
<< resSerial << " != " << res
|
|
<< std::endl ;
|
|
}
|
|
|
|
return passed ;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------
|
|
//-----------atomic view times-equal-----------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct TimesEqualAtomicViewFunctor {
|
|
|
|
typedef Kokkos::View< T* , execution_space , Kokkos::MemoryTraits< Kokkos::Atomic > > atomic_view_type ;
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
|
|
view_type input;
|
|
atomic_view_type result;
|
|
const long length;
|
|
|
|
// Wrap the result view in an atomic view, use this for operator
|
|
TimesEqualAtomicViewFunctor( const view_type & input_ , view_type & result_ , const long length_)
|
|
: input(input_)
|
|
, result(result_)
|
|
, length(length_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const long i) const {
|
|
if ( i < length && i > 0 ) {
|
|
result(0) *= (double)input(i);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
T TimesEqualAtomicView(const long input_length, const long remainder) {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef typename view_type::HostMirror host_view_type ;
|
|
|
|
const long length = input_length;
|
|
|
|
view_type input("input_view",length) ;
|
|
view_type result_view("result_view",1) ;
|
|
deep_copy(result_view, 1.0);
|
|
|
|
InitFunctor_ModTimes<T, execution_space> init_f( input , length , remainder ) ;
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), init_f );
|
|
|
|
TimesEqualAtomicViewFunctor<T,execution_space> functor(input, result_view, length);
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), functor);
|
|
Kokkos::fence();
|
|
|
|
host_view_type h_result_view = Kokkos::create_mirror_view(result_view);
|
|
Kokkos::deep_copy(h_result_view, result_view);
|
|
|
|
return (T) (h_result_view(0)) ;
|
|
}
|
|
|
|
template<class T>
|
|
T TimesEqualAtomicViewCheck( const long input_length, const long remainder ) {
|
|
|
|
//Analytical result
|
|
const long N = input_length;
|
|
T result = 1.0;
|
|
|
|
for ( long i = 2; i < N; ++i ) {
|
|
if ( i % (remainder+1) == remainder ) {
|
|
result *= 2.0;
|
|
}
|
|
else {
|
|
result *= 1.0;
|
|
}
|
|
}
|
|
|
|
return (T)result;
|
|
}
|
|
|
|
template<class T, class DeviceType>
|
|
bool TimesEqualAtomicViewTest(const long input_length)
|
|
{
|
|
const long remainder = 23;
|
|
T res = TimesEqualAtomicView<T,DeviceType>(input_length, remainder);
|
|
T resSerial = TimesEqualAtomicViewCheck<T>(input_length, remainder);
|
|
|
|
bool passed = true;
|
|
|
|
if ( resSerial != res ) {
|
|
passed = false;
|
|
|
|
std::cout << "Loop<"
|
|
<< typeid(T).name()
|
|
<< ">( test = TimesEqualAtomicViewTest"
|
|
<< " FAILED : "
|
|
<< resSerial << " != " << res
|
|
<< std::endl ;
|
|
}
|
|
|
|
return passed ;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------
|
|
//------------atomic view div-equal------------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct DivEqualAtomicViewFunctor {
|
|
|
|
typedef Kokkos::View< T , execution_space , Kokkos::MemoryTraits< Kokkos::Atomic > > atomic_view_type ;
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef Kokkos::View< T , execution_space > scalar_view_type ;
|
|
|
|
view_type input;
|
|
atomic_view_type result;
|
|
const long length;
|
|
|
|
// Wrap the result view in an atomic view, use this for operator
|
|
DivEqualAtomicViewFunctor( const view_type & input_ , scalar_view_type & result_ , const long length_)
|
|
: input(input_)
|
|
, result(result_)
|
|
, length(length_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const long i) const {
|
|
if ( i < length && i > 0 ) {
|
|
result() /= (double)(input(i));
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
T DivEqualAtomicView(const long input_length, const long remainder) {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef Kokkos::View< T , execution_space > scalar_view_type ;
|
|
typedef typename scalar_view_type::HostMirror host_scalar_view_type ;
|
|
|
|
const long length = input_length;
|
|
|
|
view_type input("input_view",length) ;
|
|
scalar_view_type result_view("result_view") ;
|
|
Kokkos::deep_copy(result_view, 12121212121);
|
|
|
|
InitFunctor_ModTimes<T, execution_space> init_f( input , length , remainder ) ;
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), init_f );
|
|
|
|
DivEqualAtomicViewFunctor<T,execution_space> functor(input, result_view, length);
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), functor);
|
|
Kokkos::fence();
|
|
|
|
host_scalar_view_type h_result_view = Kokkos::create_mirror_view(result_view);
|
|
Kokkos::deep_copy(h_result_view, result_view);
|
|
|
|
return (T) (h_result_view()) ;
|
|
}
|
|
|
|
template<class T>
|
|
T DivEqualAtomicViewCheck( const long input_length , const long remainder ) {
|
|
|
|
const long N = input_length;
|
|
T result = 12121212121.0;
|
|
for ( long i = 2; i < N; ++i ) {
|
|
if ( i % (remainder+1) == remainder ) {
|
|
result /= 1.0;
|
|
}
|
|
else {
|
|
result /= 2.0;
|
|
}
|
|
|
|
}
|
|
|
|
return (T)result;
|
|
}
|
|
|
|
template<class T, class DeviceType>
|
|
bool DivEqualAtomicViewTest(const long input_length)
|
|
{
|
|
const long remainder = 23;
|
|
|
|
T res = DivEqualAtomicView<T,DeviceType>(input_length, remainder);
|
|
T resSerial = DivEqualAtomicViewCheck<T>(input_length, remainder);
|
|
|
|
bool passed = true;
|
|
|
|
if ( resSerial != res ) {
|
|
passed = false;
|
|
|
|
std::cout << "Loop<"
|
|
<< typeid(T).name()
|
|
<< ">( test = DivEqualAtomicViewTest"
|
|
<< " FAILED : "
|
|
<< resSerial << " != " << res
|
|
<< std::endl ;
|
|
}
|
|
|
|
return passed ;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------
|
|
//------------atomic view mod-equal------------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct ModEqualAtomicViewFunctor {
|
|
|
|
typedef Kokkos::View< T , execution_space , Kokkos::MemoryTraits< Kokkos::Atomic > > atomic_view_type ;
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef Kokkos::View< T , execution_space > scalar_view_type ;
|
|
|
|
view_type input;
|
|
atomic_view_type result;
|
|
const long length;
|
|
|
|
// Wrap the result view in an atomic view, use this for operator
|
|
ModEqualAtomicViewFunctor( const view_type & input_ , scalar_view_type & result_ , const long length_)
|
|
: input(input_)
|
|
, result(result_)
|
|
, length(length_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const long i) const {
|
|
if ( i < length && i > 0 ) {
|
|
result() %= (double)(input(i));
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
T ModEqualAtomicView(const long input_length, const long remainder) {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef Kokkos::View< T , execution_space > scalar_view_type ;
|
|
typedef typename scalar_view_type::HostMirror host_scalar_view_type ;
|
|
|
|
const long length = input_length;
|
|
|
|
view_type input("input_view",length) ;
|
|
scalar_view_type result_view("result_view") ;
|
|
Kokkos::deep_copy(result_view, 12121212121);
|
|
|
|
InitFunctor_ModTimes<T, execution_space> init_f( input , length , remainder ) ;
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), init_f );
|
|
|
|
ModEqualAtomicViewFunctor<T,execution_space> functor(input, result_view, length);
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), functor);
|
|
Kokkos::fence();
|
|
|
|
host_scalar_view_type h_result_view = Kokkos::create_mirror_view(result_view);
|
|
Kokkos::deep_copy(h_result_view, result_view);
|
|
|
|
return (T) (h_result_view()) ;
|
|
}
|
|
|
|
template<class T>
|
|
T ModEqualAtomicViewCheck( const long input_length , const long remainder ) {
|
|
|
|
const long N = input_length;
|
|
T result = 12121212121;
|
|
for ( long i = 2; i < N; ++i ) {
|
|
if ( i % (remainder+1) == remainder ) {
|
|
result %= 1;
|
|
}
|
|
else {
|
|
result %= 2;
|
|
}
|
|
}
|
|
|
|
return (T)result;
|
|
}
|
|
|
|
template<class T, class DeviceType>
|
|
bool ModEqualAtomicViewTest(const long input_length)
|
|
{
|
|
|
|
static_assert( std::is_integral<T>::value, "ModEqualAtomicView Error: Type must be integral type for this unit test");
|
|
|
|
const long remainder = 23;
|
|
|
|
T res = ModEqualAtomicView<T,DeviceType>(input_length, remainder);
|
|
T resSerial = ModEqualAtomicViewCheck<T>(input_length, remainder);
|
|
|
|
bool passed = true;
|
|
|
|
if ( resSerial != res ) {
|
|
passed = false;
|
|
|
|
std::cout << "Loop<"
|
|
<< typeid(T).name()
|
|
<< ">( test = ModEqualAtomicViewTest"
|
|
<< " FAILED : "
|
|
<< resSerial << " != " << res
|
|
<< std::endl ;
|
|
}
|
|
|
|
return passed ;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------
|
|
//------------atomic view rs-equal------------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct RSEqualAtomicViewFunctor {
|
|
|
|
typedef Kokkos::View< T**** , execution_space , Kokkos::MemoryTraits< Kokkos::Atomic > > atomic_view_type ;
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef Kokkos::View< T**** , execution_space > result_view_type ;
|
|
|
|
const view_type input;
|
|
atomic_view_type result;
|
|
const long length;
|
|
const long value;
|
|
|
|
// Wrap the result view in an atomic view, use this for operator
|
|
RSEqualAtomicViewFunctor( const view_type & input_ , result_view_type & result_ , const long & length_ , const long & value_ )
|
|
: input(input_)
|
|
, result(result_)
|
|
, length(length_)
|
|
, value(value_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const long i) const {
|
|
if ( i < length ) {
|
|
if ( i % 4 == 0 ) {
|
|
result(1,0,0,0) >>= input(i);
|
|
}
|
|
else if ( i % 4 == 1 ) {
|
|
result(0,1,0,0) >>= input(i);
|
|
}
|
|
else if ( i % 4 == 2 ) {
|
|
result(0,0,1,0) >>= input(i);
|
|
}
|
|
else if ( i % 4 == 3 ) {
|
|
result(0,0,0,1) >>= input(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
T RSEqualAtomicView(const long input_length, const long value, const long remainder) {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef Kokkos::View< T**** , execution_space > result_view_type ;
|
|
typedef typename result_view_type::HostMirror host_scalar_view_type ;
|
|
|
|
const long length = input_length;
|
|
|
|
view_type input("input_view",length) ;
|
|
result_view_type result_view("result_view",2,2,2,2) ;
|
|
host_scalar_view_type h_result_view = Kokkos::create_mirror_view(result_view);
|
|
h_result_view(1,0,0,0) = value;
|
|
h_result_view(0,1,0,0) = value;
|
|
h_result_view(0,0,1,0) = value;
|
|
h_result_view(0,0,0,1) = value;
|
|
Kokkos::deep_copy( result_view , h_result_view );
|
|
|
|
|
|
InitFunctor_ModShift<T, execution_space> init_f( input , length , remainder ) ;
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), init_f );
|
|
|
|
RSEqualAtomicViewFunctor<T,execution_space> functor(input, result_view, length, value);
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), functor);
|
|
Kokkos::fence();
|
|
|
|
Kokkos::deep_copy(h_result_view, result_view);
|
|
|
|
return (T) (h_result_view(1,0,0,0)) ;
|
|
}
|
|
|
|
template<class T>
|
|
T RSEqualAtomicViewCheck( const long input_length, const long value, const long remainder ) {
|
|
|
|
T result[4] ;
|
|
result[0] = value ;
|
|
result[1] = value ;
|
|
result[2] = value ;
|
|
result[3] = value ;
|
|
|
|
T * input = new T[input_length];
|
|
for ( long i = 0; i < input_length; ++i ) {
|
|
if ( i % (remainder+1) == remainder ) {
|
|
input[i] = 1;
|
|
}
|
|
else {
|
|
input[i] = 0;
|
|
}
|
|
}
|
|
|
|
for ( long i = 0; i < input_length; ++i ) {
|
|
if ( i % 4 == 0 ) {
|
|
result[0] >>= input[i];
|
|
}
|
|
else if ( i % 4 == 1 ) {
|
|
result[1] >>= input[i];
|
|
}
|
|
else if ( i % 4 == 2 ) {
|
|
result[2] >>= input[i];
|
|
}
|
|
else if ( i % 4 == 3 ) {
|
|
result[3] >>= input[i];
|
|
}
|
|
}
|
|
delete [] input;
|
|
|
|
return (T)result[0];
|
|
}
|
|
|
|
template<class T, class DeviceType>
|
|
bool RSEqualAtomicViewTest(const long input_length)
|
|
{
|
|
|
|
static_assert( std::is_integral<T>::value, "RSEqualAtomicViewTest: Must be integral type for test");
|
|
|
|
const long remainder = 61042; //prime - 1
|
|
const long value = 1073741825; // 2^30+1
|
|
T res = RSEqualAtomicView<T,DeviceType>(input_length, value, remainder);
|
|
T resSerial = RSEqualAtomicViewCheck<T>(input_length, value, remainder);
|
|
|
|
bool passed = true;
|
|
|
|
if ( resSerial != res ) {
|
|
passed = false;
|
|
|
|
std::cout << "Loop<"
|
|
<< typeid(T).name()
|
|
<< ">( test = RSEqualAtomicViewTest"
|
|
<< " FAILED : "
|
|
<< resSerial << " != " << res
|
|
<< std::endl ;
|
|
}
|
|
|
|
return passed ;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------
|
|
//------------atomic view ls-equal------------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct LSEqualAtomicViewFunctor {
|
|
|
|
typedef Kokkos::View< T**** , execution_space , Kokkos::MemoryTraits< Kokkos::Atomic > > atomic_view_type ;
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef Kokkos::View< T**** , execution_space > result_view_type ;
|
|
|
|
view_type input;
|
|
atomic_view_type result;
|
|
const long length;
|
|
const long value;
|
|
|
|
// Wrap the result view in an atomic view, use this for operator
|
|
LSEqualAtomicViewFunctor( const view_type & input_ , result_view_type & result_ , const long & length_ , const long & value_ )
|
|
: input(input_)
|
|
, result(result_)
|
|
, length(length_)
|
|
, value(value_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const long i) const {
|
|
if ( i < length ) {
|
|
if ( i % 4 == 0 ) {
|
|
result(1,0,0,0) <<= input(i);
|
|
}
|
|
else if ( i % 4 == 1 ) {
|
|
result(0,1,0,0) <<= input(i);
|
|
}
|
|
else if ( i % 4 == 2 ) {
|
|
result(0,0,1,0) <<= input(i);
|
|
}
|
|
else if ( i % 4 == 3 ) {
|
|
result(0,0,0,1) <<= input(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
T LSEqualAtomicView(const long input_length, const long value, const long remainder) {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef Kokkos::View< T**** , execution_space > result_view_type ;
|
|
typedef typename result_view_type::HostMirror host_scalar_view_type ;
|
|
|
|
const long length = input_length;
|
|
|
|
view_type input("input_view",length) ;
|
|
result_view_type result_view("result_view",2,2,2,2) ;
|
|
host_scalar_view_type h_result_view = Kokkos::create_mirror_view(result_view);
|
|
h_result_view(1,0,0,0) = value;
|
|
h_result_view(0,1,0,0) = value;
|
|
h_result_view(0,0,1,0) = value;
|
|
h_result_view(0,0,0,1) = value;
|
|
Kokkos::deep_copy( result_view , h_result_view );
|
|
|
|
InitFunctor_ModShift<T, execution_space> init_f( input , length , remainder ) ;
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), init_f );
|
|
|
|
LSEqualAtomicViewFunctor<T,execution_space> functor(input, result_view, length, value);
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), functor);
|
|
Kokkos::fence();
|
|
|
|
Kokkos::deep_copy(h_result_view, result_view);
|
|
|
|
return (T) (h_result_view(1,0,0,0)) ;
|
|
}
|
|
|
|
template<class T>
|
|
T LSEqualAtomicViewCheck( const long input_length, const long value, const long remainder ) {
|
|
|
|
T result[4] ;
|
|
result[0] = value ;
|
|
result[1] = value ;
|
|
result[2] = value ;
|
|
result[3] = value ;
|
|
|
|
T * input = new T[input_length];
|
|
for ( long i = 0; i < input_length; ++i ) {
|
|
if ( i % (remainder+1) == remainder ) {
|
|
input[i] = 1;
|
|
}
|
|
else {
|
|
input[i] = 0;
|
|
}
|
|
}
|
|
|
|
for ( long i = 0; i < input_length; ++i ) {
|
|
if ( i % 4 == 0 ) {
|
|
result[0] <<= input[i];
|
|
}
|
|
else if ( i % 4 == 1 ) {
|
|
result[1] <<= input[i];
|
|
}
|
|
else if ( i % 4 == 2 ) {
|
|
result[2] <<= input[i];
|
|
}
|
|
else if ( i % 4 == 3 ) {
|
|
result[3] <<= input[i];
|
|
}
|
|
}
|
|
|
|
delete [] input;
|
|
|
|
return (T)result[0];
|
|
}
|
|
|
|
template<class T, class DeviceType>
|
|
bool LSEqualAtomicViewTest(const long input_length)
|
|
{
|
|
|
|
static_assert( std::is_integral<T>::value, "LSEqualAtomicViewTest: Must be integral type for test");
|
|
|
|
const long remainder = 61042; //prime - 1
|
|
const long value = 1; // 2^30+1
|
|
T res = LSEqualAtomicView<T,DeviceType>(input_length, value, remainder);
|
|
T resSerial = LSEqualAtomicViewCheck<T>(input_length, value, remainder);
|
|
|
|
bool passed = true;
|
|
|
|
if ( resSerial != res ) {
|
|
passed = false;
|
|
|
|
std::cout << "Loop<"
|
|
<< typeid(T).name()
|
|
<< ">( test = RSEqualAtomicViewTest"
|
|
<< " FAILED : "
|
|
<< resSerial << " != " << res
|
|
<< std::endl ;
|
|
}
|
|
|
|
return passed ;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------
|
|
//-----------atomic view and-equal-----------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct AndEqualAtomicViewFunctor {
|
|
|
|
typedef Kokkos::View< T* , execution_space , Kokkos::MemoryTraits< Kokkos::Atomic > > atomic_view_type ;
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
|
|
view_type input;
|
|
atomic_view_type even_odd_result;
|
|
const long length;
|
|
|
|
// Wrap the result view in an atomic view, use this for operator
|
|
AndEqualAtomicViewFunctor( const view_type & input_ , view_type & even_odd_result_ , const long length_)
|
|
: input(input_)
|
|
, even_odd_result(even_odd_result_)
|
|
, length(length_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const long i) const {
|
|
if ( i < length ) {
|
|
if ( i % 2 == 0 ) {
|
|
even_odd_result(0) &= input(i);
|
|
}
|
|
else {
|
|
even_odd_result(1) &= input(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
T AndEqualAtomicView(const long input_length) {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef typename view_type::HostMirror host_view_type ;
|
|
|
|
const long length = input_length;
|
|
|
|
view_type input("input_view",length) ;
|
|
view_type result_view("result_view",2) ;
|
|
Kokkos::deep_copy(result_view, 1);
|
|
|
|
InitFunctor_Seq<T, execution_space> init_f( input , length ) ;
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), init_f );
|
|
|
|
AndEqualAtomicViewFunctor<T,execution_space> functor(input, result_view,length);
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), functor);
|
|
Kokkos::fence();
|
|
|
|
host_view_type h_result_view = Kokkos::create_mirror_view(result_view);
|
|
Kokkos::deep_copy(h_result_view, result_view);
|
|
|
|
return (T) (h_result_view(0)) ;
|
|
}
|
|
|
|
template<class T>
|
|
T AndEqualAtomicViewCheck( const long input_length ) {
|
|
|
|
const long N = input_length;
|
|
T result[2] = {1};
|
|
for ( long i = 0; i < N; ++i ) {
|
|
if ( N % 2 == 0 ) {
|
|
result[0] &= (T)i;
|
|
}
|
|
else {
|
|
result[1] &= (T)i;
|
|
}
|
|
}
|
|
|
|
return (result[0]);
|
|
}
|
|
|
|
template<class T,class DeviceType>
|
|
bool AndEqualAtomicViewTest(long input_length)
|
|
{
|
|
|
|
static_assert( std::is_integral<T>::value, "AndEqualAtomicViewTest: Must be integral type for test");
|
|
|
|
T res = AndEqualAtomicView<T,DeviceType>(input_length);
|
|
T resSerial = AndEqualAtomicViewCheck<T>(input_length);
|
|
|
|
bool passed = true;
|
|
|
|
if ( resSerial != res ) {
|
|
passed = false;
|
|
|
|
std::cout << "Loop<"
|
|
<< typeid(T).name()
|
|
<< ">( test = AndEqualAtomicViewTest"
|
|
<< " FAILED : "
|
|
<< resSerial << " != " << res
|
|
<< std::endl ;
|
|
}
|
|
|
|
return passed ;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------
|
|
//-----------atomic view or-equal-----------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct OrEqualAtomicViewFunctor {
|
|
|
|
typedef Kokkos::View< T* , execution_space , Kokkos::MemoryTraits< Kokkos::Atomic > > atomic_view_type ;
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
|
|
view_type input;
|
|
atomic_view_type even_odd_result;
|
|
const long length;
|
|
|
|
// Wrap the result view in an atomic view, use this for operator
|
|
OrEqualAtomicViewFunctor( const view_type & input_ , view_type & even_odd_result_ , const long length_)
|
|
: input(input_)
|
|
, even_odd_result(even_odd_result_)
|
|
, length(length_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const long i) const {
|
|
if ( i < length ) {
|
|
if ( i % 2 == 0 ) {
|
|
even_odd_result(0) |= input(i);
|
|
}
|
|
else {
|
|
even_odd_result(1) |= input(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
T OrEqualAtomicView(const long input_length) {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef typename view_type::HostMirror host_view_type ;
|
|
|
|
const long length = input_length;
|
|
|
|
view_type input("input_view",length) ;
|
|
view_type result_view("result_view",2) ;
|
|
|
|
InitFunctor_Seq<T, execution_space> init_f( input , length ) ;
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), init_f );
|
|
|
|
OrEqualAtomicViewFunctor<T,execution_space> functor(input, result_view,length);
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), functor);
|
|
Kokkos::fence();
|
|
|
|
host_view_type h_result_view = Kokkos::create_mirror_view(result_view);
|
|
Kokkos::deep_copy(h_result_view, result_view);
|
|
|
|
return (T) (h_result_view(0)) ;
|
|
}
|
|
|
|
template<class T>
|
|
T OrEqualAtomicViewCheck( const long input_length ) {
|
|
|
|
const long N = input_length;
|
|
T result[2] = {0};
|
|
for ( long i = 0; i < N; ++i ) {
|
|
if ( i % 2 == 0 ) {
|
|
result[0] |= (T)i;
|
|
}
|
|
else {
|
|
result[1] |= (T)i;
|
|
}
|
|
}
|
|
|
|
return (T)(result[0]);
|
|
}
|
|
|
|
template<class T,class DeviceType>
|
|
bool OrEqualAtomicViewTest(long input_length)
|
|
{
|
|
|
|
static_assert( std::is_integral<T>::value, "OrEqualAtomicViewTest: Must be integral type for test");
|
|
|
|
T res = OrEqualAtomicView<T,DeviceType>(input_length);
|
|
T resSerial = OrEqualAtomicViewCheck<T>(input_length);
|
|
|
|
bool passed = true;
|
|
|
|
if ( resSerial != res ) {
|
|
passed = false;
|
|
|
|
std::cout << "Loop<"
|
|
<< typeid(T).name()
|
|
<< ">( test = OrEqualAtomicViewTest"
|
|
<< " FAILED : "
|
|
<< resSerial << " != " << res
|
|
<< std::endl ;
|
|
}
|
|
|
|
return passed ;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------
|
|
//-----------atomic view xor-equal-----------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T, class execution_space >
|
|
struct XOrEqualAtomicViewFunctor {
|
|
|
|
typedef Kokkos::View< T* , execution_space , Kokkos::MemoryTraits< Kokkos::Atomic > > atomic_view_type ;
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
|
|
view_type input;
|
|
atomic_view_type even_odd_result;
|
|
const long length;
|
|
|
|
// Wrap the result view in an atomic view, use this for operator
|
|
XOrEqualAtomicViewFunctor( const view_type & input_ , view_type & even_odd_result_ , const long length_)
|
|
: input(input_)
|
|
, even_odd_result(even_odd_result_)
|
|
, length(length_)
|
|
{}
|
|
|
|
KOKKOS_INLINE_FUNCTION
|
|
void operator()(const long i) const {
|
|
if ( i < length ) {
|
|
if ( i % 2 == 0 ) {
|
|
even_odd_result(0) ^= input(i);
|
|
}
|
|
else {
|
|
even_odd_result(1) ^= input(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
template<class T, class execution_space >
|
|
T XOrEqualAtomicView(const long input_length) {
|
|
|
|
typedef Kokkos::View< T* , execution_space > view_type ;
|
|
typedef typename view_type::HostMirror host_view_type ;
|
|
|
|
const long length = input_length;
|
|
|
|
view_type input("input_view",length) ;
|
|
view_type result_view("result_view",2) ;
|
|
|
|
InitFunctor_Seq<T, execution_space> init_f( input , length ) ;
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), init_f );
|
|
|
|
XOrEqualAtomicViewFunctor<T,execution_space> functor(input, result_view,length);
|
|
Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>(0, length), functor);
|
|
Kokkos::fence();
|
|
|
|
host_view_type h_result_view = Kokkos::create_mirror_view(result_view);
|
|
Kokkos::deep_copy(h_result_view, result_view);
|
|
|
|
return (T) (h_result_view(0)) ;
|
|
}
|
|
|
|
template<class T>
|
|
T XOrEqualAtomicViewCheck( const long input_length ) {
|
|
|
|
const long N = input_length;
|
|
T result[2] = {0};
|
|
for ( long i = 0; i < N; ++i ) {
|
|
if ( i % 2 == 0 ) {
|
|
result[0] ^= (T)i;
|
|
}
|
|
else {
|
|
result[1] ^= (T)i;
|
|
}
|
|
}
|
|
|
|
return (T)(result[0]);
|
|
}
|
|
|
|
template<class T,class DeviceType>
|
|
bool XOrEqualAtomicViewTest(long input_length)
|
|
{
|
|
|
|
static_assert( std::is_integral<T>::value, "XOrEqualAtomicViewTest: Must be integral type for test");
|
|
|
|
T res = XOrEqualAtomicView<T,DeviceType>(input_length);
|
|
T resSerial = XOrEqualAtomicViewCheck<T>(input_length);
|
|
|
|
bool passed = true;
|
|
|
|
if ( resSerial != res ) {
|
|
passed = false;
|
|
|
|
std::cout << "Loop<"
|
|
<< typeid(T).name()
|
|
<< ">( test = XOrEqualAtomicViewTest"
|
|
<< " FAILED : "
|
|
<< resSerial << " != " << res
|
|
<< std::endl ;
|
|
}
|
|
|
|
return passed ;
|
|
}
|
|
|
|
|
|
// inc/dec?
|
|
|
|
|
|
//---------------------------------------------------
|
|
//--------------atomic_test_control------------------
|
|
//---------------------------------------------------
|
|
|
|
template<class T,class DeviceType>
|
|
bool AtomicViewsTestIntegralType( const int length , int test )
|
|
{
|
|
static_assert( std::is_integral<T>::value, "TestAtomicViews Error: Non-integral type passed into IntegralType tests");
|
|
|
|
switch (test) {
|
|
case 1: return PlusEqualAtomicViewTest<T,DeviceType>( length );
|
|
case 2: return MinusEqualAtomicViewTest<T,DeviceType>( length );
|
|
case 3: return RSEqualAtomicViewTest<T,DeviceType>( length );
|
|
case 4: return LSEqualAtomicViewTest<T,DeviceType>( length );
|
|
case 5: return ModEqualAtomicViewTest<T,DeviceType>( length );
|
|
case 6: return AndEqualAtomicViewTest<T,DeviceType>( length );
|
|
case 7: return OrEqualAtomicViewTest<T,DeviceType>( length );
|
|
case 8: return XOrEqualAtomicViewTest<T,DeviceType>( length );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
template<class T,class DeviceType>
|
|
bool AtomicViewsTestNonIntegralType( const int length , int test )
|
|
{
|
|
switch (test) {
|
|
case 1: return PlusEqualAtomicViewTest<T,DeviceType>( length );
|
|
case 2: return MinusEqualAtomicViewTest<T,DeviceType>( length );
|
|
case 3: return TimesEqualAtomicViewTest<T,DeviceType>( length );
|
|
case 4: return DivEqualAtomicViewTest<T,DeviceType>( length );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
} // namespace
|
|
|