Files
lammps/lib/kokkos/core/unit_test/TestAtomicViews.hpp
2017-02-13 10:50:34 -07:00

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