Files
lammps/lib/kokkos/core/unit_test/TestViewMapping.hpp
2017-04-25 13:48:51 -06:00

1464 lines
52 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 <gtest/gtest.h>
#include <stdexcept>
#include <sstream>
#include <iostream>
#include <Kokkos_Core.hpp>
namespace Test {
template< class Space >
void test_view_mapping()
{
typedef typename Space::execution_space ExecSpace;
typedef Kokkos::Experimental::Impl::ViewDimension<> dim_0;
typedef Kokkos::Experimental::Impl::ViewDimension< 2 > dim_s2;
typedef Kokkos::Experimental::Impl::ViewDimension< 2, 3 > dim_s2_s3;
typedef Kokkos::Experimental::Impl::ViewDimension< 2, 3, 4 > dim_s2_s3_s4;
typedef Kokkos::Experimental::Impl::ViewDimension< 0 > dim_s0;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 3 > dim_s0_s3;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 3, 4 > dim_s0_s3_s4;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0 > dim_s0_s0;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 4 > dim_s0_s0_s4;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0 > dim_s0_s0_s0;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0, 0 > dim_s0_s0_s0_s0;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0_s0;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0_s0_s0;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0, 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0_s0_s0_s0;
// Fully static dimensions should not be larger than an int.
ASSERT_LE( sizeof( dim_0 ), sizeof( int ) );
ASSERT_LE( sizeof( dim_s2 ), sizeof( int ) );
ASSERT_LE( sizeof( dim_s2_s3 ), sizeof( int ) );
ASSERT_LE( sizeof( dim_s2_s3_s4 ), sizeof( int ) );
// Rank 1 is size_t.
ASSERT_EQ( sizeof( dim_s0 ), sizeof( size_t ) );
ASSERT_EQ( sizeof( dim_s0_s3 ), sizeof( size_t ) );
ASSERT_EQ( sizeof( dim_s0_s3_s4 ), sizeof( size_t ) );
// Allow for padding.
ASSERT_LE( sizeof( dim_s0_s0 ), 2 * sizeof( size_t ) );
ASSERT_LE( sizeof( dim_s0_s0_s4 ), 2 * sizeof( size_t ) );
ASSERT_LE( sizeof( dim_s0_s0_s0 ), 4 * sizeof( size_t ) );
ASSERT_EQ( sizeof( dim_s0_s0_s0_s0 ), 4 * sizeof( unsigned ) );
ASSERT_LE( sizeof( dim_s0_s0_s0_s0_s0 ), 6 * sizeof( unsigned ) );
ASSERT_EQ( sizeof( dim_s0_s0_s0_s0_s0_s0 ), 6 * sizeof( unsigned ) );
ASSERT_LE( sizeof( dim_s0_s0_s0_s0_s0_s0_s0 ), 8 * sizeof( unsigned ) );
ASSERT_EQ( sizeof( dim_s0_s0_s0_s0_s0_s0_s0_s0 ), 8 * sizeof( unsigned ) );
static_assert( int( dim_0::rank ) == int( 0 ), "" );
static_assert( int( dim_0::rank_dynamic ) == int( 0 ), "" );
static_assert( int( dim_0::ArgN0 ) == 1, "" );
static_assert( int( dim_0::ArgN1 ) == 1, "" );
static_assert( int( dim_0::ArgN2 ) == 1, "" );
static_assert( int( dim_s2::rank ) == int( 1 ), "" );
static_assert( int( dim_s2::rank_dynamic ) == int( 0 ), "" );
static_assert( int( dim_s2::ArgN0 ) == 2, "" );
static_assert( int( dim_s2::ArgN1 ) == 1, "" );
static_assert( int( dim_s2_s3::rank ) == int( 2 ), "" );
static_assert( int( dim_s2_s3::rank_dynamic ) == int( 0 ), "" );
static_assert( int( dim_s2_s3::ArgN0 ) == 2, "" );
static_assert( int( dim_s2_s3::ArgN1 ) == 3, "" );
static_assert( int( dim_s2_s3::ArgN2 ) == 1, "" );
static_assert( int( dim_s2_s3_s4::rank ) == int( 3 ), "" );
static_assert( int( dim_s2_s3_s4::rank_dynamic ) == int( 0 ), "" );
static_assert( int( dim_s2_s3_s4::ArgN0 ) == 2, "" );
static_assert( int( dim_s2_s3_s4::ArgN1 ) == 3, "" );
static_assert( int( dim_s2_s3_s4::ArgN2 ) == 4, "" );
static_assert( int( dim_s2_s3_s4::ArgN3 ) == 1, "" );
static_assert( int( dim_s0::rank ) == int( 1 ), "" );
static_assert( int( dim_s0::rank_dynamic ) == int( 1 ), "" );
static_assert( int( dim_s0_s3::rank ) == int( 2 ), "" );
static_assert( int( dim_s0_s3::rank_dynamic ) == int( 1 ), "" );
static_assert( int( dim_s0_s3::ArgN0 ) == 0, "" );
static_assert( int( dim_s0_s3::ArgN1 ) == 3, "" );
static_assert( int( dim_s0_s3_s4::rank ) == int( 3 ), "" );
static_assert( int( dim_s0_s3_s4::rank_dynamic ) == int( 1 ), "" );
static_assert( int( dim_s0_s3_s4::ArgN0 ) == 0, "" );
static_assert( int( dim_s0_s3_s4::ArgN1 ) == 3, "" );
static_assert( int( dim_s0_s3_s4::ArgN2 ) == 4, "" );
static_assert( int( dim_s0_s0_s4::rank ) == int( 3 ), "" );
static_assert( int( dim_s0_s0_s4::rank_dynamic ) == int( 2 ), "" );
static_assert( int( dim_s0_s0_s4::ArgN0 ) == 0, "" );
static_assert( int( dim_s0_s0_s4::ArgN1 ) == 0, "" );
static_assert( int( dim_s0_s0_s4::ArgN2 ) == 4, "" );
static_assert( int( dim_s0_s0_s0::rank ) == int( 3 ), "" );
static_assert( int( dim_s0_s0_s0::rank_dynamic ) == int( 3 ), "" );
static_assert( int( dim_s0_s0_s0_s0::rank ) == int( 4 ), "" );
static_assert( int( dim_s0_s0_s0_s0::rank_dynamic ) == int( 4 ), "" );
static_assert( int( dim_s0_s0_s0_s0_s0::rank ) == int( 5 ), "" );
static_assert( int( dim_s0_s0_s0_s0_s0::rank_dynamic ) == int( 5 ), "" );
static_assert( int( dim_s0_s0_s0_s0_s0_s0::rank ) == int( 6 ), "" );
static_assert( int( dim_s0_s0_s0_s0_s0_s0::rank_dynamic ) == int( 6 ), "" );
static_assert( int( dim_s0_s0_s0_s0_s0_s0_s0::rank ) == int( 7 ), "" );
static_assert( int( dim_s0_s0_s0_s0_s0_s0_s0::rank_dynamic ) == int( 7 ), "" );
static_assert( int( dim_s0_s0_s0_s0_s0_s0_s0_s0::rank ) == int( 8 ), "" );
static_assert( int( dim_s0_s0_s0_s0_s0_s0_s0_s0::rank_dynamic ) == int( 8 ), "" );
dim_s0 d1( 2, 3, 4, 5, 6, 7, 8, 9 );
dim_s0_s0 d2( 2, 3, 4, 5, 6, 7, 8, 9 );
dim_s0_s0_s0 d3( 2, 3, 4, 5, 6, 7, 8, 9 );
dim_s0_s0_s0_s0 d4( 2, 3, 4, 5, 6, 7, 8, 9 );
ASSERT_EQ( d1.N0, 2 );
ASSERT_EQ( d2.N0, 2 );
ASSERT_EQ( d3.N0, 2 );
ASSERT_EQ( d4.N0, 2 );
ASSERT_EQ( d1.N1, 1 );
ASSERT_EQ( d2.N1, 3 );
ASSERT_EQ( d3.N1, 3 );
ASSERT_EQ( d4.N1, 3 );
ASSERT_EQ( d1.N2, 1 );
ASSERT_EQ( d2.N2, 1 );
ASSERT_EQ( d3.N2, 4 );
ASSERT_EQ( d4.N2, 4 );
ASSERT_EQ( d1.N3, 1 );
ASSERT_EQ( d2.N3, 1 );
ASSERT_EQ( d3.N3, 1 );
ASSERT_EQ( d4.N3, 5 );
//----------------------------------------
typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s0, Kokkos::LayoutStride > stride_s0_s0_s0;
//----------------------------------------
// Static dimension.
{
typedef Kokkos::Experimental::Impl::ViewOffset< dim_s2_s3_s4, Kokkos::LayoutLeft > left_s2_s3_s4;
ASSERT_EQ( sizeof( left_s2_s3_s4 ), sizeof( dim_s2_s3_s4 ) );
left_s2_s3_s4 off3;
stride_s0_s0_s0 stride3( off3 );
ASSERT_EQ( off3.stride_0(), 1 );
ASSERT_EQ( off3.stride_1(), 2 );
ASSERT_EQ( off3.stride_2(), 6 );
ASSERT_EQ( off3.span(), 24 );
ASSERT_EQ( off3.stride_0(), stride3.stride_0() );
ASSERT_EQ( off3.stride_1(), stride3.stride_1() );
ASSERT_EQ( off3.stride_2(), stride3.stride_2() );
ASSERT_EQ( off3.span(), stride3.span() );
int offset = 0;
for ( int k = 0; k < 4; ++k )
for ( int j = 0; j < 3; ++j )
for ( int i = 0; i < 2; ++i, ++offset )
{
ASSERT_EQ( off3( i, j, k ), offset );
ASSERT_EQ( stride3( i, j, k ), off3( i, j, k ) );
}
}
//----------------------------------------
// Small dimension is unpadded.
{
typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutLeft > left_s0_s0_s4;
left_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >()
, Kokkos::LayoutLeft( 2, 3, 0, 0, 0, 0, 0, 0 ) );
stride_s0_s0_s0 stride3( dyn_off3 );
ASSERT_EQ( dyn_off3.m_dim.rank, 3 );
ASSERT_EQ( dyn_off3.m_dim.N0, 2 );
ASSERT_EQ( dyn_off3.m_dim.N1, 3 );
ASSERT_EQ( dyn_off3.m_dim.N2, 4 );
ASSERT_EQ( dyn_off3.m_dim.N3, 1 );
ASSERT_EQ( dyn_off3.size(), 2 * 3 * 4 );
const Kokkos::LayoutLeft layout = dyn_off3.layout();
ASSERT_EQ( layout.dimension[0], 2 );
ASSERT_EQ( layout.dimension[1], 3 );
ASSERT_EQ( layout.dimension[2], 4 );
ASSERT_EQ( layout.dimension[3], 1 );
ASSERT_EQ( layout.dimension[4], 1 );
ASSERT_EQ( layout.dimension[5], 1 );
ASSERT_EQ( layout.dimension[6], 1 );
ASSERT_EQ( layout.dimension[7], 1 );
ASSERT_EQ( stride3.m_dim.rank, 3 );
ASSERT_EQ( stride3.m_dim.N0, 2 );
ASSERT_EQ( stride3.m_dim.N1, 3 );
ASSERT_EQ( stride3.m_dim.N2, 4 );
ASSERT_EQ( stride3.m_dim.N3, 1 );
ASSERT_EQ( stride3.size(), 2 * 3 * 4 );
int offset = 0;
for ( int k = 0; k < 4; ++k )
for ( int j = 0; j < 3; ++j )
for ( int i = 0; i < 2; ++i, ++offset )
{
ASSERT_EQ( offset, dyn_off3( i, j, k ) );
ASSERT_EQ( stride3( i, j, k ), dyn_off3( i, j, k ) );
}
ASSERT_EQ( dyn_off3.span(), offset );
ASSERT_EQ( stride3.span(), dyn_off3.span() );
}
//----------------------------------------
// Large dimension is likely padded.
{
constexpr int N0 = 2000;
constexpr int N1 = 300;
typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutLeft > left_s0_s0_s4;
left_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >()
, Kokkos::LayoutLeft( N0, N1, 0, 0, 0, 0, 0, 0 ) );
stride_s0_s0_s0 stride3( dyn_off3 );
ASSERT_EQ( dyn_off3.m_dim.rank, 3 );
ASSERT_EQ( dyn_off3.m_dim.N0, N0 );
ASSERT_EQ( dyn_off3.m_dim.N1, N1 );
ASSERT_EQ( dyn_off3.m_dim.N2, 4 );
ASSERT_EQ( dyn_off3.m_dim.N3, 1 );
ASSERT_EQ( dyn_off3.size(), N0 * N1 * 4 );
ASSERT_EQ( stride3.m_dim.rank, 3 );
ASSERT_EQ( stride3.m_dim.N0, N0 );
ASSERT_EQ( stride3.m_dim.N1, N1 );
ASSERT_EQ( stride3.m_dim.N2, 4 );
ASSERT_EQ( stride3.m_dim.N3, 1 );
ASSERT_EQ( stride3.size(), N0 * N1 * 4 );
ASSERT_EQ( stride3.span(), dyn_off3.span() );
int offset = 0;
for ( int k = 0; k < 4; ++k )
for ( int j = 0; j < N1; ++j )
for ( int i = 0; i < N0; ++i )
{
ASSERT_LE( offset, dyn_off3( i, j, k ) );
ASSERT_EQ( stride3( i, j, k ), dyn_off3( i, j, k ) );
offset = dyn_off3( i, j, k ) + 1;
}
ASSERT_LE( offset, dyn_off3.span() );
}
//----------------------------------------
// Static dimension.
{
typedef Kokkos::Experimental::Impl::ViewOffset< dim_s2_s3_s4, Kokkos::LayoutRight > right_s2_s3_s4;
ASSERT_EQ( sizeof( right_s2_s3_s4 ), sizeof( dim_s2_s3_s4 ) );
right_s2_s3_s4 off3;
stride_s0_s0_s0 stride3( off3 );
ASSERT_EQ( off3.stride_0(), 12 );
ASSERT_EQ( off3.stride_1(), 4 );
ASSERT_EQ( off3.stride_2(), 1 );
ASSERT_EQ( off3.dimension_0(), stride3.dimension_0() );
ASSERT_EQ( off3.dimension_1(), stride3.dimension_1() );
ASSERT_EQ( off3.dimension_2(), stride3.dimension_2() );
ASSERT_EQ( off3.stride_0(), stride3.stride_0() );
ASSERT_EQ( off3.stride_1(), stride3.stride_1() );
ASSERT_EQ( off3.stride_2(), stride3.stride_2() );
ASSERT_EQ( off3.span(), stride3.span() );
int offset = 0;
for ( int i = 0; i < 2; ++i )
for ( int j = 0; j < 3; ++j )
for ( int k = 0; k < 4; ++k, ++offset )
{
ASSERT_EQ( off3( i, j, k ), offset );
ASSERT_EQ( off3( i, j, k ), stride3( i, j, k ) );
}
ASSERT_EQ( off3.span(), offset );
}
//----------------------------------------
// Small dimension is unpadded.
{
typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutRight > right_s0_s0_s4;
right_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >()
, Kokkos::LayoutRight( 2, 3, 0, 0, 0, 0, 0, 0 ) );
stride_s0_s0_s0 stride3( dyn_off3 );
ASSERT_EQ( dyn_off3.m_dim.rank, 3 );
ASSERT_EQ( dyn_off3.m_dim.N0, 2 );
ASSERT_EQ( dyn_off3.m_dim.N1, 3 );
ASSERT_EQ( dyn_off3.m_dim.N2, 4 );
ASSERT_EQ( dyn_off3.m_dim.N3, 1 );
ASSERT_EQ( dyn_off3.size(), 2 * 3 * 4 );
ASSERT_EQ( dyn_off3.dimension_0(), stride3.dimension_0() );
ASSERT_EQ( dyn_off3.dimension_1(), stride3.dimension_1() );
ASSERT_EQ( dyn_off3.dimension_2(), stride3.dimension_2() );
ASSERT_EQ( dyn_off3.stride_0(), stride3.stride_0() );
ASSERT_EQ( dyn_off3.stride_1(), stride3.stride_1() );
ASSERT_EQ( dyn_off3.stride_2(), stride3.stride_2() );
ASSERT_EQ( dyn_off3.span(), stride3.span() );
int offset = 0;
for ( int i = 0; i < 2; ++i )
for ( int j = 0; j < 3; ++j )
for ( int k = 0; k < 4; ++k, ++offset )
{
ASSERT_EQ( offset, dyn_off3( i, j, k ) );
ASSERT_EQ( dyn_off3( i, j, k ), stride3( i, j, k ) );
}
ASSERT_EQ( dyn_off3.span(), offset );
}
//----------------------------------------
// Large dimension is likely padded.
{
constexpr int N0 = 2000;
constexpr int N1 = 300;
typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutRight > right_s0_s0_s4;
right_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >()
, Kokkos::LayoutRight( N0, N1, 0, 0, 0, 0, 0, 0 ) );
stride_s0_s0_s0 stride3( dyn_off3 );
ASSERT_EQ( dyn_off3.m_dim.rank, 3 );
ASSERT_EQ( dyn_off3.m_dim.N0, N0 );
ASSERT_EQ( dyn_off3.m_dim.N1, N1 );
ASSERT_EQ( dyn_off3.m_dim.N2, 4 );
ASSERT_EQ( dyn_off3.m_dim.N3, 1 );
ASSERT_EQ( dyn_off3.size(), N0 * N1 * 4 );
ASSERT_EQ( dyn_off3.dimension_0(), stride3.dimension_0() );
ASSERT_EQ( dyn_off3.dimension_1(), stride3.dimension_1() );
ASSERT_EQ( dyn_off3.dimension_2(), stride3.dimension_2() );
ASSERT_EQ( dyn_off3.stride_0(), stride3.stride_0() );
ASSERT_EQ( dyn_off3.stride_1(), stride3.stride_1() );
ASSERT_EQ( dyn_off3.stride_2(), stride3.stride_2() );
ASSERT_EQ( dyn_off3.span(), stride3.span() );
int offset = 0;
for ( int i = 0; i < N0; ++i )
for ( int j = 0; j < N1; ++j )
for ( int k = 0; k < 4; ++k )
{
ASSERT_LE( offset, dyn_off3( i, j, k ) );
ASSERT_EQ( dyn_off3( i, j, k ), stride3( i, j, k ) );
offset = dyn_off3( i, j, k ) + 1;
}
ASSERT_LE( offset, dyn_off3.span() );
}
//----------------------------------------
// Subview.
{
// Mapping rank 4 to rank 3
typedef Kokkos::Experimental::Impl::SubviewExtents< 4, 3 > SubviewExtents;
constexpr int N0 = 1000;
constexpr int N1 = 2000;
constexpr int N2 = 3000;
constexpr int N3 = 4000;
Kokkos::Experimental::Impl::ViewDimension< N0, N1, N2, N3 > dim;
SubviewExtents tmp( dim
, N0 / 2
, Kokkos::Experimental::ALL
, std::pair< int, int >( N2 / 4, 10 + N2 / 4 )
, Kokkos::pair< int, int >( N3 / 4, 20 + N3 / 4 )
);
ASSERT_EQ( tmp.domain_offset( 0 ), N0 / 2 );
ASSERT_EQ( tmp.domain_offset( 1 ), 0 );
ASSERT_EQ( tmp.domain_offset( 2 ), N2 / 4 );
ASSERT_EQ( tmp.domain_offset( 3 ), N3 / 4 );
ASSERT_EQ( tmp.range_index( 0 ), 1 );
ASSERT_EQ( tmp.range_index( 1 ), 2 );
ASSERT_EQ( tmp.range_index( 2 ), 3 );
ASSERT_EQ( tmp.range_extent( 0 ), N1 );
ASSERT_EQ( tmp.range_extent( 1 ), 10 );
ASSERT_EQ( tmp.range_extent( 2 ), 20 );
}
{
constexpr int N0 = 2000;
constexpr int N1 = 300;
constexpr int sub_N0 = 1000;
constexpr int sub_N1 = 200;
constexpr int sub_N2 = 4;
typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutLeft > left_s0_s0_s4;
left_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >()
, Kokkos::LayoutLeft( N0, N1, 0, 0, 0, 0, 0, 0 ) );
Kokkos::Experimental::Impl::SubviewExtents< 3, 3 >
sub( dyn_off3.m_dim
, Kokkos::pair< int, int >( 0, sub_N0 )
, Kokkos::pair< int, int >( 0, sub_N1 )
, Kokkos::pair< int, int >( 0, sub_N2 )
);
stride_s0_s0_s0 stride3( dyn_off3, sub );
ASSERT_EQ( stride3.dimension_0(), sub_N0 );
ASSERT_EQ( stride3.dimension_1(), sub_N1 );
ASSERT_EQ( stride3.dimension_2(), sub_N2 );
ASSERT_EQ( stride3.size(), sub_N0 * sub_N1 * sub_N2 );
ASSERT_EQ( dyn_off3.stride_0(), stride3.stride_0() );
ASSERT_EQ( dyn_off3.stride_1(), stride3.stride_1() );
ASSERT_EQ( dyn_off3.stride_2(), stride3.stride_2() );
ASSERT_GE( dyn_off3.span() , stride3.span() );
for ( int k = 0; k < sub_N2; ++k )
for ( int j = 0; j < sub_N1; ++j )
for ( int i = 0; i < sub_N0; ++i )
{
ASSERT_EQ( stride3( i, j, k ), dyn_off3( i, j, k ) );
}
}
{
constexpr int N0 = 2000;
constexpr int N1 = 300;
constexpr int sub_N0 = 1000;
constexpr int sub_N1 = 200;
constexpr int sub_N2 = 4;
typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutRight > right_s0_s0_s4;
right_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >()
, Kokkos::LayoutRight( N0, N1, 0, 0, 0, 0, 0, 0 ) );
Kokkos::Experimental::Impl::SubviewExtents< 3, 3 >
sub( dyn_off3.m_dim
, Kokkos::pair< int, int >( 0, sub_N0 )
, Kokkos::pair< int, int >( 0, sub_N1 )
, Kokkos::pair< int, int >( 0, sub_N2 )
);
stride_s0_s0_s0 stride3( dyn_off3, sub );
ASSERT_EQ( stride3.dimension_0(), sub_N0 );
ASSERT_EQ( stride3.dimension_1(), sub_N1 );
ASSERT_EQ( stride3.dimension_2(), sub_N2 );
ASSERT_EQ( stride3.size(), sub_N0 * sub_N1 * sub_N2 );
ASSERT_EQ( dyn_off3.stride_0(), stride3.stride_0() );
ASSERT_EQ( dyn_off3.stride_1(), stride3.stride_1() );
ASSERT_EQ( dyn_off3.stride_2(), stride3.stride_2() );
ASSERT_GE( dyn_off3.span() , stride3.span() );
for ( int i = 0; i < sub_N0; ++i )
for ( int j = 0; j < sub_N1; ++j )
for ( int k = 0; k < sub_N2; ++k )
{
ASSERT_EQ( stride3( i, j, k ), dyn_off3( i, j, k ) );
}
}
//----------------------------------------
// View data analysis.
{
using namespace Kokkos::Experimental::Impl;
static_assert( rank_dynamic<>::value == 0, "" );
static_assert( rank_dynamic< 1 >::value == 0, "" );
static_assert( rank_dynamic< 0 >::value == 1, "" );
static_assert( rank_dynamic< 0, 1 >::value == 1, "" );
static_assert( rank_dynamic< 0, 0, 1 >::value == 2, "" );
}
{
using namespace Kokkos::Experimental::Impl;
typedef ViewArrayAnalysis< int[] > a_int_r1;
typedef ViewArrayAnalysis< int**[4][5][6] > a_int_r5;
typedef ViewArrayAnalysis< const int[] > a_const_int_r1;
typedef ViewArrayAnalysis< const int**[4][5][6] > a_const_int_r5;
static_assert( a_int_r1::dimension::rank == 1, "" );
static_assert( a_int_r1::dimension::rank_dynamic == 1, "" );
static_assert( a_int_r5::dimension::ArgN0 == 0, "" );
static_assert( a_int_r5::dimension::ArgN1 == 0, "" );
static_assert( a_int_r5::dimension::ArgN2 == 4, "" );
static_assert( a_int_r5::dimension::ArgN3 == 5, "" );
static_assert( a_int_r5::dimension::ArgN4 == 6, "" );
static_assert( a_int_r5::dimension::ArgN5 == 1, "" );
static_assert( std::is_same< typename a_int_r1::dimension, ViewDimension<0> >::value, "" );
static_assert( std::is_same< typename a_int_r1::non_const_value_type, int >::value, "" );
static_assert( a_const_int_r1::dimension::rank == 1, "" );
static_assert( a_const_int_r1::dimension::rank_dynamic == 1, "" );
static_assert( std::is_same< typename a_const_int_r1::dimension, ViewDimension<0> >::value, "" );
static_assert( std::is_same< typename a_const_int_r1::non_const_value_type, int >::value, "" );
static_assert( a_const_int_r5::dimension::rank == 5, "" );
static_assert( a_const_int_r5::dimension::rank_dynamic == 2, "" );
static_assert( a_const_int_r5::dimension::ArgN0 == 0, "" );
static_assert( a_const_int_r5::dimension::ArgN1 == 0, "" );
static_assert( a_const_int_r5::dimension::ArgN2 == 4, "" );
static_assert( a_const_int_r5::dimension::ArgN3 == 5, "" );
static_assert( a_const_int_r5::dimension::ArgN4 == 6, "" );
static_assert( a_const_int_r5::dimension::ArgN5 == 1, "" );
static_assert( std::is_same< typename a_const_int_r5::dimension, ViewDimension<0, 0, 4, 5, 6> >::value, "" );
static_assert( std::is_same< typename a_const_int_r5::non_const_value_type, int >::value, "" );
static_assert( a_int_r5::dimension::rank == 5, "" );
static_assert( a_int_r5::dimension::rank_dynamic == 2, "" );
static_assert( std::is_same< typename a_int_r5::dimension, ViewDimension<0, 0, 4, 5, 6> >::value, "" );
static_assert( std::is_same< typename a_int_r5::non_const_value_type, int >::value, "" );
}
{
using namespace Kokkos::Experimental::Impl;
typedef int t_i4[4];
// Dimensions of t_i4 are appended to the multdimensional array.
typedef ViewArrayAnalysis< t_i4 ***[3] > a_int_r5;
static_assert( a_int_r5::dimension::rank == 5, "" );
static_assert( a_int_r5::dimension::rank_dynamic == 3, "" );
static_assert( a_int_r5::dimension::ArgN0 == 0, "" );
static_assert( a_int_r5::dimension::ArgN1 == 0, "" );
static_assert( a_int_r5::dimension::ArgN2 == 0, "" );
static_assert( a_int_r5::dimension::ArgN3 == 3, "" );
static_assert( a_int_r5::dimension::ArgN4 == 4, "" );
static_assert( std::is_same< typename a_int_r5::non_const_value_type, int >::value, "" );
}
{
using namespace Kokkos::Experimental::Impl;
typedef ViewDataAnalysis< const int[], void > a_const_int_r1;
static_assert( std::is_same< typename a_const_int_r1::specialize, void >::value, "" );
static_assert( std::is_same< typename a_const_int_r1::dimension, Kokkos::Experimental::Impl::ViewDimension<0> >::value, "" );
static_assert( std::is_same< typename a_const_int_r1::type, const int * >::value, "" );
static_assert( std::is_same< typename a_const_int_r1::value_type, const int >::value, "" );
static_assert( std::is_same< typename a_const_int_r1::scalar_array_type, const int * >::value, "" );
static_assert( std::is_same< typename a_const_int_r1::const_type, const int * >::value, "" );
static_assert( std::is_same< typename a_const_int_r1::const_value_type, const int >::value, "" );
static_assert( std::is_same< typename a_const_int_r1::const_scalar_array_type, const int * >::value, "" );
static_assert( std::is_same< typename a_const_int_r1::non_const_type, int * >::value, "" );
static_assert( std::is_same< typename a_const_int_r1::non_const_value_type, int >::value, "" );
typedef ViewDataAnalysis< const int**[4], void > a_const_int_r3;
static_assert( std::is_same< typename a_const_int_r3::specialize, void >::value, "" );
static_assert( std::is_same< typename a_const_int_r3::dimension, Kokkos::Experimental::Impl::ViewDimension<0, 0, 4> >::value, "" );
static_assert( std::is_same< typename a_const_int_r3::type, const int**[4] >::value, "" );
static_assert( std::is_same< typename a_const_int_r3::value_type, const int >::value, "" );
static_assert( std::is_same< typename a_const_int_r3::scalar_array_type, const int**[4] >::value, "" );
static_assert( std::is_same< typename a_const_int_r3::const_type, const int**[4] >::value, "" );
static_assert( std::is_same< typename a_const_int_r3::const_value_type, const int >::value, "" );
static_assert( std::is_same< typename a_const_int_r3::const_scalar_array_type, const int**[4] >::value, "" );
static_assert( std::is_same< typename a_const_int_r3::non_const_type, int**[4] >::value, "" );
static_assert( std::is_same< typename a_const_int_r3::non_const_value_type, int >::value, "" );
static_assert( std::is_same< typename a_const_int_r3::non_const_scalar_array_type, int**[4] >::value, "" );
// std::cout << "typeid( const int**[4] ).name() = " << typeid( const int**[4] ).name() << std::endl;
}
//----------------------------------------
{
constexpr int N = 10;
typedef Kokkos::View< int*, Space > T;
typedef Kokkos::View< const int*, Space > C;
int data[N];
T vr1( data, N ); // View of non-const.
C cr1( vr1 ); // View of const from view of non-const.
C cr2( (const int *) data, N );
// Generate static_assert error:
// T tmp( cr1 );
ASSERT_EQ( vr1.span(), N );
ASSERT_EQ( cr1.span(), N );
ASSERT_EQ( vr1.data(), & data[0] );
ASSERT_EQ( cr1.data(), & data[0] );
ASSERT_TRUE( ( std::is_same< typename T::data_type , int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::const_data_type , const int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::non_const_data_type, int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::scalar_array_type , int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::const_scalar_array_type , const int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::non_const_scalar_array_type, int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::value_type , int >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::const_value_type , const int >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::non_const_value_type, int >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::memory_space, typename Space::memory_space >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::reference_type, int & >::value ) );
ASSERT_EQ( T::Rank, 1 );
ASSERT_TRUE( ( std::is_same< typename C::data_type , const int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename C::const_data_type , const int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename C::non_const_data_type, int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename C::scalar_array_type , const int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename C::const_scalar_array_type , const int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename C::non_const_scalar_array_type, int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename C::value_type , const int >::value ) );
ASSERT_TRUE( ( std::is_same< typename C::const_value_type , const int >::value ) );
ASSERT_TRUE( ( std::is_same< typename C::non_const_value_type, int >::value ) );
ASSERT_TRUE( ( std::is_same< typename C::memory_space, typename Space::memory_space >::value ) );
ASSERT_TRUE( ( std::is_same< typename C::reference_type, const int & >::value ) );
ASSERT_EQ( C::Rank, 1 );
ASSERT_EQ( vr1.dimension_0(), N );
if ( Kokkos::Impl::SpaceAccessibility< Kokkos::HostSpace, typename Space::memory_space >::accessible ) {
for ( int i = 0; i < N; ++i ) data[i] = i + 1;
for ( int i = 0; i < N; ++i ) ASSERT_EQ( vr1[i], i + 1 );
for ( int i = 0; i < N; ++i ) ASSERT_EQ( cr1[i], i + 1 );
{
T tmp( vr1 );
for ( int i = 0; i < N; ++i ) ASSERT_EQ( tmp[i], i + 1 );
for ( int i = 0; i < N; ++i ) vr1( i ) = i + 2;
for ( int i = 0; i < N; ++i ) ASSERT_EQ( tmp[i], i + 2 );
}
for ( int i = 0; i < N; ++i ) ASSERT_EQ( vr1[i], i + 2 );
}
}
{
constexpr int N = 10;
typedef Kokkos::View< int*, Space > T;
typedef Kokkos::View< const int*, Space > C;
T vr1( "vr1", N );
C cr1( vr1 );
ASSERT_TRUE( ( std::is_same< typename T::data_type , int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::const_data_type , const int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::non_const_data_type, int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::scalar_array_type , int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::const_scalar_array_type , const int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::non_const_scalar_array_type, int* >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::value_type , int >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::const_value_type , const int >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::non_const_value_type, int >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::memory_space, typename Space::memory_space >::value ) );
ASSERT_TRUE( ( std::is_same< typename T::reference_type, int & >::value ) );
ASSERT_EQ( T::Rank, 1 );
ASSERT_EQ( vr1.dimension_0(), N );
if ( Kokkos::Impl::SpaceAccessibility< Kokkos::HostSpace, typename Space::memory_space >::accessible ) {
for ( int i = 0; i < N; ++i ) vr1( i ) = i + 1;
for ( int i = 0; i < N; ++i ) ASSERT_EQ( vr1[i], i + 1 );
for ( int i = 0; i < N; ++i ) ASSERT_EQ( cr1[i], i + 1 );
{
T tmp( vr1 );
for ( int i = 0; i < N; ++i ) ASSERT_EQ( tmp[i], i + 1 );
for ( int i = 0; i < N; ++i ) vr1( i ) = i + 2;
for ( int i = 0; i < N; ++i ) ASSERT_EQ( tmp[i], i + 2 );
}
for ( int i = 0; i < N; ++i ) ASSERT_EQ( vr1[i], i + 2 );
}
}
// Testing proper handling of zero-length allocations.
{
constexpr int N = 0;
typedef Kokkos::View< int*, Space > T;
typedef Kokkos::View< const int*, Space > C;
T vr1( "vr1", N );
C cr1( vr1 );
ASSERT_EQ( vr1.dimension_0(), 0 );
ASSERT_EQ( cr1.dimension_0(), 0 );
}
// Testing using space instance for allocation.
// The execution space of the memory space must be available for view data initialization.
if ( std::is_same< ExecSpace, typename ExecSpace::memory_space::execution_space >::value ) {
using namespace Kokkos::Experimental;
typedef typename ExecSpace::memory_space memory_space;
typedef View< int*, memory_space > V;
constexpr int N = 10;
memory_space mem_space;
V v( "v", N );
V va( view_alloc(), N );
V vb( view_alloc( "vb" ), N );
V vc( view_alloc( "vc", AllowPadding ), N );
V vd( view_alloc( "vd", WithoutInitializing ), N );
V ve( view_alloc( "ve", WithoutInitializing, AllowPadding ), N );
V vf( view_alloc( "vf", mem_space, WithoutInitializing, AllowPadding ), N );
V vg( view_alloc( mem_space, "vg", WithoutInitializing, AllowPadding ), N );
V vh( view_alloc( WithoutInitializing, AllowPadding ), N );
V vi( view_alloc( WithoutInitializing ), N );
V vj( view_alloc( std::string( "vj" ), AllowPadding ), N );
V vk( view_alloc( mem_space, std::string( "vk" ), AllowPadding ), N );
}
{
typedef Kokkos::ViewTraits< int***, Kokkos::LayoutStride, ExecSpace > traits_t;
typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0 > dims_t;
typedef Kokkos::Experimental::Impl::ViewOffset< dims_t, Kokkos::LayoutStride > offset_t;
Kokkos::LayoutStride stride;
stride.dimension[0] = 3;
stride.dimension[1] = 4;
stride.dimension[2] = 5;
stride.stride[0] = 4;
stride.stride[1] = 1;
stride.stride[2] = 12;
const offset_t offset( std::integral_constant< unsigned, 0 >(), stride );
ASSERT_EQ( offset.dimension_0(), 3 );
ASSERT_EQ( offset.dimension_1(), 4 );
ASSERT_EQ( offset.dimension_2(), 5 );
ASSERT_EQ( offset.stride_0(), 4 );
ASSERT_EQ( offset.stride_1(), 1 );
ASSERT_EQ( offset.stride_2(), 12 );
ASSERT_EQ( offset.span(), 60 );
ASSERT_TRUE( offset.span_is_contiguous() );
Kokkos::Experimental::Impl::ViewMapping< traits_t, void >
v( Kokkos::Experimental::Impl::ViewCtorProp< int* >( (int*) 0 ), stride );
}
{
typedef Kokkos::View< int**, Space > V;
typedef typename V::HostMirror M;
typedef typename Kokkos::View< int**, Space >::array_layout layout_type;
constexpr int N0 = 10;
constexpr int N1 = 11;
V a( "a", N0, N1 );
M b = Kokkos::Experimental::create_mirror( a );
M c = Kokkos::Experimental::create_mirror_view( a );
M d;
for ( int i0 = 0; i0 < N0; ++i0 )
for ( int i1 = 0; i1 < N1; ++i1 )
{
b( i0, i1 ) = 1 + i0 + i1 * N0;
}
Kokkos::Experimental::deep_copy( a, b );
Kokkos::Experimental::deep_copy( c, a );
for ( int i0 = 0; i0 < N0; ++i0 )
for ( int i1 = 0; i1 < N1; ++i1 )
{
ASSERT_EQ( b( i0, i1 ), c( i0, i1 ) );
}
Kokkos::Experimental::resize( b, 5, 6 );
for ( int i0 = 0; i0 < 5; ++i0 )
for ( int i1 = 0; i1 < 6; ++i1 )
{
int val = 1 + i0 + i1 * N0;
ASSERT_EQ( b( i0, i1 ), c( i0, i1 ) );
ASSERT_EQ( b( i0, i1 ), val );
}
Kokkos::Experimental::realloc( c, 5, 6 );
Kokkos::Experimental::realloc( d, 5, 6 );
ASSERT_EQ( b.dimension_0(), 5 );
ASSERT_EQ( b.dimension_1(), 6 );
ASSERT_EQ( c.dimension_0(), 5 );
ASSERT_EQ( c.dimension_1(), 6 );
ASSERT_EQ( d.dimension_0(), 5 );
ASSERT_EQ( d.dimension_1(), 6 );
layout_type layout( 7, 8 );
Kokkos::Experimental::resize( b, layout );
for ( int i0 = 0; i0 < 7; ++i0 )
for ( int i1 = 6; i1 < 8; ++i1 )
{
b( i0, i1 ) = 1 + i0 + i1 * N0;
}
for ( int i0 = 5; i0 < 7; ++i0 )
for ( int i1 = 0; i1 < 8; ++i1 )
{
b( i0, i1 ) = 1 + i0 + i1 * N0;
}
for ( int i0 = 0; i0 < 7; ++i0 )
for ( int i1 = 0; i1 < 8; ++i1 )
{
int val = 1 + i0 + i1 * N0;
ASSERT_EQ( b( i0, i1 ), val );
}
Kokkos::Experimental::realloc( c, layout );
Kokkos::Experimental::realloc( d, layout );
ASSERT_EQ( b.dimension_0(), 7 );
ASSERT_EQ( b.dimension_1(), 8 );
ASSERT_EQ( c.dimension_0(), 7 );
ASSERT_EQ( c.dimension_1(), 8 );
ASSERT_EQ( d.dimension_0(), 7 );
ASSERT_EQ( d.dimension_1(), 8 );
}
{
typedef Kokkos::View< int**, Kokkos::LayoutStride, Space > V;
typedef typename V::HostMirror M;
typedef typename Kokkos::View< int**, Kokkos::LayoutStride, Space >::array_layout layout_type;
constexpr int N0 = 10;
constexpr int N1 = 11;
const int dimensions[] = { N0, N1 };
const int order[] = { 1, 0 };
V a( "a", Kokkos::LayoutStride::order_dimensions( 2, order, dimensions ) );
M b = Kokkos::Experimental::create_mirror( a );
M c = Kokkos::Experimental::create_mirror_view( a );
M d;
for ( int i0 = 0; i0 < N0; ++i0 )
for ( int i1 = 0; i1 < N1; ++i1 )
{
b( i0, i1 ) = 1 + i0 + i1 * N0;
}
Kokkos::Experimental::deep_copy( a, b );
Kokkos::Experimental::deep_copy( c, a );
for ( int i0 = 0; i0 < N0; ++i0 )
for ( int i1 = 0; i1 < N1; ++i1 )
{
ASSERT_EQ( b( i0, i1 ), c( i0, i1 ) );
}
const int dimensions2[] = { 7, 8 };
const int order2[] = { 1, 0 };
layout_type layout = layout_type::order_dimensions( 2, order2, dimensions2 );
Kokkos::Experimental::resize( b, layout );
for ( int i0 = 0; i0 < 7; ++i0 )
for ( int i1 = 0; i1 < 8; ++i1 )
{
int val = 1 + i0 + i1 * N0;
ASSERT_EQ( b( i0, i1 ), c( i0, i1 ) );
ASSERT_EQ( b( i0, i1 ), val );
}
Kokkos::Experimental::realloc( c, layout );
Kokkos::Experimental::realloc( d, layout );
ASSERT_EQ( b.dimension_0(), 7 );
ASSERT_EQ( b.dimension_1(), 8 );
ASSERT_EQ( c.dimension_0(), 7 );
ASSERT_EQ( c.dimension_1(), 8 );
ASSERT_EQ( d.dimension_0(), 7 );
ASSERT_EQ( d.dimension_1(), 8 );
}
{
typedef Kokkos::View< int*, Space > V;
typedef Kokkos::View< int*, Space, Kokkos::MemoryUnmanaged > U;
V a( "a", 10 );
ASSERT_EQ( a.use_count(), 1 );
V b = a;
ASSERT_EQ( a.use_count(), 2 );
ASSERT_EQ( b.use_count(), 2 );
{
U c = b; // 'c' is compile-time unmanaged.
ASSERT_EQ( a.use_count(), 2 );
ASSERT_EQ( b.use_count(), 2 );
ASSERT_EQ( c.use_count(), 2 );
V d = c; // 'd' is run-time unmanaged.
ASSERT_EQ( a.use_count(), 2 );
ASSERT_EQ( b.use_count(), 2 );
ASSERT_EQ( c.use_count(), 2 );
ASSERT_EQ( d.use_count(), 2 );
}
ASSERT_EQ( a.use_count(), 2 );
ASSERT_EQ( b.use_count(), 2 );
b = V();
ASSERT_EQ( a.use_count(), 1 );
ASSERT_EQ( b.use_count(), 0 );
#if !defined( KOKKOS_ENABLE_CUDA_LAMBDA )
// Cannot launch host lambda when CUDA lambda is enabled.
typedef typename Kokkos::Impl::HostMirror< Space >::Space::execution_space host_exec_space;
Kokkos::parallel_for( Kokkos::RangePolicy< host_exec_space >( 0, 10 ), KOKKOS_LAMBDA ( int i ) {
// 'a' is captured by copy, and the capture mechanism converts 'a' to an
// unmanaged copy. When the parallel dispatch accepts a move for the
// lambda, this count should become 1.
ASSERT_EQ( a.use_count(), 2 );
V x = a;
ASSERT_EQ( a.use_count(), 2 );
ASSERT_EQ( x.use_count(), 2 );
});
#endif // #if !defined( KOKKOS_ENABLE_CUDA_LAMBDA )
}
}
template< class Space >
struct TestViewMappingSubview
{
typedef typename Space::execution_space ExecSpace;
typedef typename Space::memory_space MemSpace;
typedef Kokkos::pair< int, int > range;
enum { AN = 10 };
typedef Kokkos::View< int*, ExecSpace > AT;
typedef Kokkos::View< const int*, ExecSpace > ACT;
typedef Kokkos::Subview< AT, range > AS;
enum { BN0 = 10, BN1 = 11, BN2 = 12 };
typedef Kokkos::View< int***, ExecSpace > BT;
typedef Kokkos::Subview< BT, range, range, range > BS;
enum { CN0 = 10, CN1 = 11, CN2 = 12 };
typedef Kokkos::View< int***[13][14], ExecSpace > CT;
typedef Kokkos::Subview< CT, range, range, range, int, int > CS;
enum { DN0 = 10, DN1 = 11, DN2 = 12, DN3 = 13, DN4 = 14 };
typedef Kokkos::View< int***[DN3][DN4], ExecSpace > DT;
typedef Kokkos::Subview< DT, int, range, range, range, int > DS;
typedef Kokkos::View< int***[13][14], Kokkos::LayoutLeft, ExecSpace > DLT;
typedef Kokkos::Subview< DLT, range, int, int, int, int > DLS1;
static_assert( DLS1::rank == 1 && std::is_same< typename DLS1::array_layout, Kokkos::LayoutLeft >::value
, "Subview layout error for rank 1 subview of left-most range of LayoutLeft" );
typedef Kokkos::View< int***[13][14], Kokkos::LayoutRight, ExecSpace > DRT;
typedef Kokkos::Subview< DRT, int, int, int, int, range > DRS1;
static_assert( DRS1::rank == 1 && std::is_same< typename DRS1::array_layout, Kokkos::LayoutRight >::value
, "Subview layout error for rank 1 subview of right-most range of LayoutRight" );
AT Aa;
AS Ab;
ACT Ac;
BT Ba;
BS Bb;
CT Ca;
CS Cb;
DT Da;
DS Db;
TestViewMappingSubview()
: Aa( "Aa", AN )
, Ab( Kokkos::Experimental::subview( Aa, std::pair< int, int >( 1, AN - 1 ) ) )
, Ac( Aa, std::pair< int, int >( 1, AN - 1 ) )
, Ba( "Ba", BN0, BN1, BN2 )
, Bb( Kokkos::Experimental::subview( Ba
, std::pair< int, int >( 1, BN0 - 1 )
, std::pair< int, int >( 1, BN1 - 1 )
, std::pair< int, int >( 1, BN2 - 1 )
) )
, Ca( "Ca", CN0, CN1, CN2 )
, Cb( Kokkos::Experimental::subview( Ca
, std::pair< int, int >( 1, CN0 - 1 )
, std::pair< int, int >( 1, CN1 - 1 )
, std::pair< int, int >( 1, CN2 - 1 )
, 1
, 2
) )
, Da( "Da", DN0, DN1, DN2 )
, Db( Kokkos::Experimental::subview( Da
, 1
, std::pair< int, int >( 1, DN1 - 1 )
, std::pair< int, int >( 1, DN2 - 1 )
, std::pair< int, int >( 1, DN3 - 1 )
, 2
) )
{}
KOKKOS_INLINE_FUNCTION
void operator()( const int, long & error_count ) const
{
auto Ad = Kokkos::Experimental::subview< Kokkos::MemoryUnmanaged >( Aa, Kokkos::pair< int, int >( 1, AN - 1 ) );
for ( int i = 1; i < AN - 1; ++i ) if( & Aa[i] != & Ab[i - 1] ) ++error_count;
for ( int i = 1; i < AN - 1; ++i ) if( & Aa[i] != & Ac[i - 1] ) ++error_count;
for ( int i = 1; i < AN - 1; ++i ) if( & Aa[i] != & Ad[i - 1] ) ++error_count;
for ( int i2 = 1; i2 < BN2 - 1; ++i2 )
for ( int i1 = 1; i1 < BN1 - 1; ++i1 )
for ( int i0 = 1; i0 < BN0 - 1; ++i0 )
{
if ( & Ba( i0, i1, i2 ) != & Bb( i0 - 1, i1 - 1, i2 - 1 ) ) ++error_count;
}
for ( int i2 = 1; i2 < CN2 - 1; ++i2 )
for ( int i1 = 1; i1 < CN1 - 1; ++i1 )
for ( int i0 = 1; i0 < CN0 - 1; ++i0 )
{
if ( & Ca( i0, i1, i2, 1, 2 ) != & Cb( i0 - 1, i1 - 1, i2 - 1 ) ) ++error_count;
}
for ( int i2 = 1; i2 < DN3 - 1; ++i2 )
for ( int i1 = 1; i1 < DN2 - 1; ++i1 )
for ( int i0 = 1; i0 < DN1 - 1; ++i0 )
{
if ( & Da( 1, i0, i1, i2, 2 ) != & Db( i0 - 1, i1 - 1, i2 - 1 ) ) ++error_count;
}
}
static void run()
{
TestViewMappingSubview self;
ASSERT_EQ( self.Aa.dimension_0(), AN );
ASSERT_EQ( self.Ab.dimension_0(), AN - 2 );
ASSERT_EQ( self.Ac.dimension_0(), AN - 2 );
ASSERT_EQ( self.Ba.dimension_0(), BN0 );
ASSERT_EQ( self.Ba.dimension_1(), BN1 );
ASSERT_EQ( self.Ba.dimension_2(), BN2 );
ASSERT_EQ( self.Bb.dimension_0(), BN0 - 2 );
ASSERT_EQ( self.Bb.dimension_1(), BN1 - 2 );
ASSERT_EQ( self.Bb.dimension_2(), BN2 - 2 );
ASSERT_EQ( self.Ca.dimension_0(), CN0 );
ASSERT_EQ( self.Ca.dimension_1(), CN1 );
ASSERT_EQ( self.Ca.dimension_2(), CN2 );
ASSERT_EQ( self.Ca.dimension_3(), 13 );
ASSERT_EQ( self.Ca.dimension_4(), 14 );
ASSERT_EQ( self.Cb.dimension_0(), CN0 - 2 );
ASSERT_EQ( self.Cb.dimension_1(), CN1 - 2 );
ASSERT_EQ( self.Cb.dimension_2(), CN2 - 2 );
ASSERT_EQ( self.Da.dimension_0(), DN0 );
ASSERT_EQ( self.Da.dimension_1(), DN1 );
ASSERT_EQ( self.Da.dimension_2(), DN2 );
ASSERT_EQ( self.Da.dimension_3(), DN3 );
ASSERT_EQ( self.Da.dimension_4(), DN4 );
ASSERT_EQ( self.Db.dimension_0(), DN1 - 2 );
ASSERT_EQ( self.Db.dimension_1(), DN2 - 2 );
ASSERT_EQ( self.Db.dimension_2(), DN3 - 2 );
ASSERT_EQ( self.Da.stride_1(), self.Db.stride_0() );
ASSERT_EQ( self.Da.stride_2(), self.Db.stride_1() );
ASSERT_EQ( self.Da.stride_3(), self.Db.stride_2() );
long error_count = -1;
Kokkos::parallel_reduce( Kokkos::RangePolicy< ExecSpace >( 0, 1 ), self, error_count );
ASSERT_EQ( error_count, 0 );
}
};
template< class Space >
void test_view_mapping_subview()
{
typedef typename Space::execution_space ExecSpace;
TestViewMappingSubview< ExecSpace >::run();
}
/*--------------------------------------------------------------------------*/
template< class ViewType >
struct TestViewMapOperator {
static_assert( ViewType::reference_type_is_lvalue_reference
, "Test only valid for lvalue reference type" );
const ViewType v;
KOKKOS_INLINE_FUNCTION
void test_left( size_t i0, long & error_count ) const
{
typename ViewType::value_type * const base_ptr = & v( 0, 0, 0, 0, 0, 0, 0, 0 );
const size_t n1 = v.dimension_1();
const size_t n2 = v.dimension_2();
const size_t n3 = v.dimension_3();
const size_t n4 = v.dimension_4();
const size_t n5 = v.dimension_5();
const size_t n6 = v.dimension_6();
const size_t n7 = v.dimension_7();
long offset = 0;
for ( size_t i7 = 0; i7 < n7; ++i7 )
for ( size_t i6 = 0; i6 < n6; ++i6 )
for ( size_t i5 = 0; i5 < n5; ++i5 )
for ( size_t i4 = 0; i4 < n4; ++i4 )
for ( size_t i3 = 0; i3 < n3; ++i3 )
for ( size_t i2 = 0; i2 < n2; ++i2 )
for ( size_t i1 = 0; i1 < n1; ++i1 )
{
const long d = & v( i0, i1, i2, i3, i4, i5, i6, i7 ) - base_ptr;
if ( d < offset ) ++error_count;
offset = d;
}
if ( v.span() <= size_t( offset ) ) ++error_count;
}
KOKKOS_INLINE_FUNCTION
void test_right( size_t i0, long & error_count ) const
{
typename ViewType::value_type * const base_ptr = & v( 0, 0, 0, 0, 0, 0, 0, 0 );
const size_t n1 = v.dimension_1();
const size_t n2 = v.dimension_2();
const size_t n3 = v.dimension_3();
const size_t n4 = v.dimension_4();
const size_t n5 = v.dimension_5();
const size_t n6 = v.dimension_6();
const size_t n7 = v.dimension_7();
long offset = 0;
for ( size_t i1 = 0; i1 < n1; ++i1 )
for ( size_t i2 = 0; i2 < n2; ++i2 )
for ( size_t i3 = 0; i3 < n3; ++i3 )
for ( size_t i4 = 0; i4 < n4; ++i4 )
for ( size_t i5 = 0; i5 < n5; ++i5 )
for ( size_t i6 = 0; i6 < n6; ++i6 )
for ( size_t i7 = 0; i7 < n7; ++i7 )
{
const long d = & v( i0, i1, i2, i3, i4, i5, i6, i7 ) - base_ptr;
if ( d < offset ) ++error_count;
offset = d;
}
if ( v.span() <= size_t( offset ) ) ++error_count;
}
KOKKOS_INLINE_FUNCTION
void operator()( size_t i, long & error_count ) const
{
if ( std::is_same< typename ViewType::array_layout, Kokkos::LayoutLeft >::value ) {
test_left( i, error_count );
}
else if ( std::is_same< typename ViewType::array_layout, Kokkos::LayoutRight >::value ) {
test_right( i, error_count );
}
}
constexpr static size_t N0 = 10;
constexpr static size_t N1 = 9;
constexpr static size_t N2 = 8;
constexpr static size_t N3 = 7;
constexpr static size_t N4 = 6;
constexpr static size_t N5 = 5;
constexpr static size_t N6 = 4;
constexpr static size_t N7 = 3;
TestViewMapOperator() : v( "Test", N0, N1, N2, N3, N4, N5, N6, N7 ) {}
static void run()
{
TestViewMapOperator self;
ASSERT_EQ( self.v.dimension_0(), ( 0 < ViewType::rank ? N0 : 1 ) );
ASSERT_EQ( self.v.dimension_1(), ( 1 < ViewType::rank ? N1 : 1 ) );
ASSERT_EQ( self.v.dimension_2(), ( 2 < ViewType::rank ? N2 : 1 ) );
ASSERT_EQ( self.v.dimension_3(), ( 3 < ViewType::rank ? N3 : 1 ) );
ASSERT_EQ( self.v.dimension_4(), ( 4 < ViewType::rank ? N4 : 1 ) );
ASSERT_EQ( self.v.dimension_5(), ( 5 < ViewType::rank ? N5 : 1 ) );
ASSERT_EQ( self.v.dimension_6(), ( 6 < ViewType::rank ? N6 : 1 ) );
ASSERT_EQ( self.v.dimension_7(), ( 7 < ViewType::rank ? N7 : 1 ) );
ASSERT_LE( self.v.dimension_0() *
self.v.dimension_1() *
self.v.dimension_2() *
self.v.dimension_3() *
self.v.dimension_4() *
self.v.dimension_5() *
self.v.dimension_6() *
self.v.dimension_7()
, self.v.span() );
long error_count;
Kokkos::RangePolicy< typename ViewType::execution_space > range( 0, self.v.dimension_0() );
Kokkos::parallel_reduce( range, self, error_count );
ASSERT_EQ( 0, error_count );
}
};
template< class Space >
void test_view_mapping_operator()
{
typedef typename Space::execution_space ExecSpace;
TestViewMapOperator< Kokkos::View<int, Kokkos::LayoutLeft, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int*, Kokkos::LayoutLeft, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int**, Kokkos::LayoutLeft, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int***, Kokkos::LayoutLeft, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int****, Kokkos::LayoutLeft, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int*****, Kokkos::LayoutLeft, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int******, Kokkos::LayoutLeft, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int*******, Kokkos::LayoutLeft, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int, Kokkos::LayoutRight, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int*, Kokkos::LayoutRight, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int**, Kokkos::LayoutRight, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int***, Kokkos::LayoutRight, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int****, Kokkos::LayoutRight, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int*****, Kokkos::LayoutRight, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int******, Kokkos::LayoutRight, ExecSpace> >::run();
TestViewMapOperator< Kokkos::View<int*******, Kokkos::LayoutRight, ExecSpace> >::run();
}
/*--------------------------------------------------------------------------*/
template< class Space >
struct TestViewMappingAtomic {
typedef typename Space::execution_space ExecSpace;
typedef typename Space::memory_space MemSpace;
typedef Kokkos::MemoryTraits< Kokkos::Atomic > mem_trait;
typedef Kokkos::View< int *, ExecSpace > T;
typedef Kokkos::View< int *, ExecSpace, mem_trait > T_atom;
T x;
T_atom x_atom;
constexpr static size_t N = 100000;
struct TagInit {};
struct TagUpdate {};
struct TagVerify {};
KOKKOS_INLINE_FUNCTION
void operator()( const TagInit &, const int i ) const
{ x( i ) = i; }
KOKKOS_INLINE_FUNCTION
void operator()( const TagUpdate &, const int i ) const
{ x_atom( i % 2 ) += 1; }
KOKKOS_INLINE_FUNCTION
void operator()( const TagVerify &, const int i, long & error_count ) const
{
if ( i < 2 ) { if ( x( i ) != int( i + N / 2 ) ) ++error_count; }
else { if ( x( i ) != int( i ) ) ++error_count; }
}
TestViewMappingAtomic()
: x( "x", N )
, x_atom( x )
{}
static void run()
{
ASSERT_TRUE( T::reference_type_is_lvalue_reference );
ASSERT_FALSE( T_atom::reference_type_is_lvalue_reference );
TestViewMappingAtomic self;
Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace, TagInit >( 0, N ), self );
Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace, TagUpdate >( 0, N ), self );
long error_count = -1;
Kokkos::parallel_reduce( Kokkos::RangePolicy< ExecSpace, TagVerify >( 0, N ), self, error_count );
ASSERT_EQ( 0, error_count );
typename TestViewMappingAtomic::T_atom::HostMirror x_host = Kokkos::create_mirror_view( self.x );
Kokkos::deep_copy( x_host, self.x );
error_count = -1;
Kokkos::parallel_reduce( Kokkos::RangePolicy< Kokkos::DefaultHostExecutionSpace, TagVerify >( 0, N ),
[=] ( const TagVerify &, const int i, long & tmp_error_count )
{
if ( i < 2 ) {
if ( x_host( i ) != int( i + N / 2 ) ) ++tmp_error_count ;
}
else {
if ( x_host( i ) != int( i ) ) ++tmp_error_count ;
}
}, error_count);
ASSERT_EQ( 0 , error_count );
Kokkos::deep_copy( self.x, x_host );
}
};
/*--------------------------------------------------------------------------*/
template< class Space >
struct TestViewMappingClassValue {
typedef typename Space::execution_space ExecSpace;
typedef typename Space::memory_space MemSpace;
struct ValueType {
KOKKOS_INLINE_FUNCTION
ValueType()
{
#if 0
#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA )
printf( "TestViewMappingClassValue construct on Cuda\n" );
#elif defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST )
printf( "TestViewMappingClassValue construct on Host\n" );
#else
printf( "TestViewMappingClassValue construct unknown\n" );
#endif
#endif
}
KOKKOS_INLINE_FUNCTION
~ValueType()
{
#if 0
#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA )
printf( "TestViewMappingClassValue destruct on Cuda\n" );
#elif defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST )
printf( "TestViewMappingClassValue destruct on Host\n" );
#else
printf( "TestViewMappingClassValue destruct unknown\n" );
#endif
#endif
}
};
static void run()
{
using namespace Kokkos::Experimental;
ExecSpace::fence();
{
View< ValueType, ExecSpace > a( "a" );
ExecSpace::fence();
}
ExecSpace::fence();
}
};
} // namespace Test