Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F77637543
TestTaskPolicy.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Thu, Aug 15, 15:11
Size
34 KB
Mime Type
text/x-c
Expires
Sat, Aug 17, 15:11 (1 d, 22 h)
Engine
blob
Format
Raw Data
Handle
19893454
Attached To
rLAMMPS lammps
TestTaskPolicy.hpp
View Options
/*
//@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
*/
#ifndef KOKKOS_UNITTEST_TASKPOLICY_HPP
#define KOKKOS_UNITTEST_TASKPOLICY_HPP
#include <stdio.h>
#include <iostream>
#include <cmath>
#include <Kokkos_TaskPolicy.hpp>
#if defined( KOKKOS_ENABLE_TASKPOLICY )
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
namespace TestTaskPolicy {
namespace {
long eval_fib( long n )
{
constexpr long mask = 0x03 ;
long fib[4] = { 0 , 1 , 1 , 2 };
for ( long i = 2 ; i <= n ; ++i ) {
fib[ i & mask ] = fib[ ( i - 1 ) & mask ] + fib[ ( i - 2 ) & mask ];
}
return fib[ n & mask ];
}
}
template< typename Space >
struct TestFib
{
typedef Kokkos::TaskPolicy<Space> policy_type ;
typedef Kokkos::Future<long,Space> future_type ;
typedef long value_type ;
policy_type policy ;
future_type fib_m1 ;
future_type fib_m2 ;
const value_type n ;
KOKKOS_INLINE_FUNCTION
TestFib( const policy_type & arg_policy , const value_type arg_n )
: policy(arg_policy)
, fib_m1() , fib_m2()
, n( arg_n )
{}
KOKKOS_INLINE_FUNCTION
void operator()( typename policy_type::member_type & , value_type & result )
{
#if 0
printf( "\nTestFib(%ld) %d %d\n"
, n
, int( ! fib_m1.is_null() )
, int( ! fib_m2.is_null() )
);
#endif
if ( n < 2 ) {
result = n ;
}
else if ( ! fib_m2.is_null() && ! fib_m1.is_null() ) {
result = fib_m1.get() + fib_m2.get();
}
else {
// Spawn new children and respawn myself to sum their results:
// Spawn lower value at higher priority as it has a shorter
// path to completion.
fib_m2 = policy.task_spawn( TestFib(policy,n-2)
, Kokkos::TaskSingle
, Kokkos::TaskHighPriority );
fib_m1 = policy.task_spawn( TestFib(policy,n-1)
, Kokkos::TaskSingle );
Kokkos::Future<Space> dep[] = { fib_m1 , fib_m2 };
Kokkos::Future<Space> fib_all = policy.when_all( 2 , dep );
if ( ! fib_m2.is_null() && ! fib_m1.is_null() && ! fib_all.is_null() ) {
// High priority to retire this branch
policy.respawn( this , Kokkos::TaskHighPriority , fib_all );
}
else {
#if 0
printf( "TestFib(%ld) insufficient memory alloc_capacity(%d) task_max(%d) task_accum(%ld)\n"
, n
, policy.allocation_capacity()
, policy.allocated_task_count_max()
, policy.allocated_task_count_accum()
);
#endif
Kokkos::abort("TestFib insufficient memory");
}
}
}
static void run( int i , size_t MemoryCapacity = 16000 )
{
typedef typename policy_type::memory_space memory_space ;
enum { Log2_SuperBlockSize = 12 };
policy_type root_policy( memory_space() , MemoryCapacity , Log2_SuperBlockSize );
future_type f = root_policy.host_spawn( TestFib(root_policy,i) , Kokkos::TaskSingle );
Kokkos::wait( root_policy );
ASSERT_EQ( eval_fib(i) , f.get() );
#if 0
fprintf( stdout , "\nTestFib::run(%d) spawn_size(%d) when_all_size(%d) alloc_capacity(%d) task_max(%d) task_accum(%ld)\n"
, i
, int(root_policy.template spawn_allocation_size<TestFib>())
, int(root_policy.when_all_allocation_size(2))
, root_policy.allocation_capacity()
, root_policy.allocated_task_count_max()
, root_policy.allocated_task_count_accum()
);
fflush( stdout );
#endif
}
};
} // namespace TestTaskPolicy
//----------------------------------------------------------------------------
namespace TestTaskPolicy {
template< class Space >
struct TestTaskDependence {
typedef Kokkos::TaskPolicy<Space> policy_type ;
typedef Kokkos::Future<Space> future_type ;
typedef Kokkos::View<long,Space> accum_type ;
typedef void value_type ;
policy_type m_policy ;
accum_type m_accum ;
long m_count ;
KOKKOS_INLINE_FUNCTION
TestTaskDependence( long n
, const policy_type & arg_policy
, const accum_type & arg_accum )
: m_policy( arg_policy )
, m_accum( arg_accum )
, m_count( n )
{}
KOKKOS_INLINE_FUNCTION
void operator()( typename policy_type::member_type & )
{
enum { CHUNK = 8 };
const int n = CHUNK < m_count ? CHUNK : m_count ;
if ( 1 < m_count ) {
future_type f[ CHUNK ] ;
const int inc = ( m_count + n - 1 ) / n ;
for ( int i = 0 ; i < n ; ++i ) {
long begin = i * inc ;
long count = begin + inc < m_count ? inc : m_count - begin ;
f[i] = m_policy.task_spawn( TestTaskDependence(count,m_policy,m_accum) , Kokkos::TaskSingle );
}
m_count = 0 ;
m_policy.respawn( this , m_policy.when_all( n , f ) );
}
else if ( 1 == m_count ) {
Kokkos::atomic_increment( & m_accum() );
}
}
static void run( int n )
{
typedef typename policy_type::memory_space memory_space ;
// enum { MemoryCapacity = 4000 }; // Triggers infinite loop in memory pool
enum { MemoryCapacity = 16000 };
enum { Log2_SuperBlockSize = 12 };
policy_type policy( memory_space() , MemoryCapacity , Log2_SuperBlockSize );
accum_type accum("accum");
typename accum_type::HostMirror host_accum =
Kokkos::create_mirror_view( accum );
policy.host_spawn( TestTaskDependence(n,policy,accum) , Kokkos::TaskSingle );
Kokkos::wait( policy );
Kokkos::deep_copy( host_accum , accum );
ASSERT_EQ( host_accum() , n );
}
};
} // namespace TestTaskPolicy
//----------------------------------------------------------------------------
namespace TestTaskPolicy {
template< class ExecSpace >
struct TestTaskTeam {
//enum { SPAN = 8 };
enum { SPAN = 33 };
//enum { SPAN = 1 };
typedef void value_type ;
typedef Kokkos::TaskPolicy<ExecSpace> policy_type ;
typedef Kokkos::Future<ExecSpace> future_type ;
typedef Kokkos::View<long*,ExecSpace> view_type ;
policy_type policy ;
future_type future ;
view_type parfor_result ;
view_type parreduce_check ;
view_type parscan_result ;
view_type parscan_check ;
const long nvalue ;
KOKKOS_INLINE_FUNCTION
TestTaskTeam( const policy_type & arg_policy
, const view_type & arg_parfor_result
, const view_type & arg_parreduce_check
, const view_type & arg_parscan_result
, const view_type & arg_parscan_check
, const long arg_nvalue )
: policy(arg_policy)
, future()
, parfor_result( arg_parfor_result )
, parreduce_check( arg_parreduce_check )
, parscan_result( arg_parscan_result )
, parscan_check( arg_parscan_check )
, nvalue( arg_nvalue )
{}
KOKKOS_INLINE_FUNCTION
void operator()( typename policy_type::member_type & member )
{
const long end = nvalue + 1 ;
const long begin = 0 < end - SPAN ? end - SPAN : 0 ;
if ( 0 < begin && future.is_null() ) {
if ( member.team_rank() == 0 ) {
future = policy.task_spawn
( TestTaskTeam( policy ,
parfor_result ,
parreduce_check,
parscan_result,
parscan_check,
begin - 1 )
, Kokkos::TaskTeam );
assert( ! future.is_null() );
policy.respawn( this , future );
}
return ;
}
Kokkos::parallel_for( Kokkos::TeamThreadRange(member,begin,end)
, [&]( int i ) { parfor_result[i] = i ; }
);
// test parallel_reduce without join
long tot = 0;
long expected = (begin+end-1)*(end-begin)*0.5;
Kokkos::parallel_reduce( Kokkos::TeamThreadRange(member,begin,end)
, [&]( int i, long &res) { res += parfor_result[i]; }
, tot);
Kokkos::parallel_for( Kokkos::TeamThreadRange(member,begin,end)
, [&]( int i ) { parreduce_check[i] = expected-tot ; }
);
// test parallel_reduce with join
tot = 0;
Kokkos::parallel_reduce( Kokkos::TeamThreadRange(member,begin,end)
, [&]( int i, long &res) { res += parfor_result[i]; }
, [&]( long& val1, const long& val2) { val1 += val2; }
, tot);
Kokkos::parallel_for( Kokkos::TeamThreadRange(member,begin,end)
, [&]( int i ) { parreduce_check[i] += expected-tot ; }
);
#if 0
// test parallel_scan
// Exclusive scan
Kokkos::parallel_scan<long>( Kokkos::TeamThreadRange(member,begin,end)
, [&]( int i, long &val , const bool final ) {
if ( final ) { parscan_result[i] = val; }
val += i;
}
);
if ( member.team_rank() == 0 ) {
for ( long i = begin ; i < end ; ++i ) {
parscan_check[i] = (i*(i-1)-begin*(begin-1))*0.5-parscan_result[i];
}
}
// Inclusive scan
Kokkos::parallel_scan<long>( Kokkos::TeamThreadRange(member,begin,end)
, [&]( int i, long &val , const bool final ) {
val += i;
if ( final ) { parscan_result[i] = val; }
}
);
if ( member.team_rank() == 0 ) {
for ( long i = begin ; i < end ; ++i ) {
parscan_check[i] += (i*(i+1)-begin*(begin-1))*0.5-parscan_result[i];
}
}
#endif
}
static void run( long n )
{
// const unsigned memory_capacity = 10000 ; // causes memory pool infinite loop
// const unsigned memory_capacity = 100000 ; // fails with SPAN=1 for serial and OMP
const unsigned memory_capacity = 400000 ;
policy_type root_policy( typename policy_type::memory_space()
, memory_capacity );
view_type root_parfor_result("parfor_result",n+1);
view_type root_parreduce_check("parreduce_check",n+1);
view_type root_parscan_result("parscan_result",n+1);
view_type root_parscan_check("parscan_check",n+1);
typename view_type::HostMirror
host_parfor_result = Kokkos::create_mirror_view( root_parfor_result );
typename view_type::HostMirror
host_parreduce_check = Kokkos::create_mirror_view( root_parreduce_check );
typename view_type::HostMirror
host_parscan_result = Kokkos::create_mirror_view( root_parscan_result );
typename view_type::HostMirror
host_parscan_check = Kokkos::create_mirror_view( root_parscan_check );
future_type f = root_policy.host_spawn(
TestTaskTeam( root_policy ,
root_parfor_result ,
root_parreduce_check ,
root_parscan_result,
root_parscan_check,
n ) ,
Kokkos::TaskTeam );
Kokkos::wait( root_policy );
Kokkos::deep_copy( host_parfor_result , root_parfor_result );
Kokkos::deep_copy( host_parreduce_check , root_parreduce_check );
Kokkos::deep_copy( host_parscan_result , root_parscan_result );
Kokkos::deep_copy( host_parscan_check , root_parscan_check );
for ( long i = 0 ; i <= n ; ++i ) {
const long answer = i ;
if ( host_parfor_result(i) != answer ) {
std::cerr << "TestTaskTeam::run ERROR parallel_for result(" << i << ") = "
<< host_parfor_result(i) << " != " << answer << std::endl ;
}
if ( host_parreduce_check(i) != 0 ) {
std::cerr << "TestTaskTeam::run ERROR parallel_reduce check(" << i << ") = "
<< host_parreduce_check(i) << " != 0" << std::endl ;
} //TODO
if ( host_parscan_check(i) != 0 ) {
std::cerr << "TestTaskTeam::run ERROR parallel_scan check(" << i << ") = "
<< host_parscan_check(i) << " != 0" << std::endl ;
}
}
}
};
template< class ExecSpace >
struct TestTaskTeamValue {
enum { SPAN = 8 };
typedef long value_type ;
typedef Kokkos::TaskPolicy<ExecSpace> policy_type ;
typedef Kokkos::Future<value_type,ExecSpace> future_type ;
typedef Kokkos::View<long*,ExecSpace> view_type ;
policy_type policy ;
future_type future ;
view_type result ;
const long nvalue ;
KOKKOS_INLINE_FUNCTION
TestTaskTeamValue( const policy_type & arg_policy
, const view_type & arg_result
, const long arg_nvalue )
: policy(arg_policy)
, future()
, result( arg_result )
, nvalue( arg_nvalue )
{}
KOKKOS_INLINE_FUNCTION
void operator()( typename policy_type::member_type const & member
, value_type & final )
{
const long end = nvalue + 1 ;
const long begin = 0 < end - SPAN ? end - SPAN : 0 ;
if ( 0 < begin && future.is_null() ) {
if ( member.team_rank() == 0 ) {
future = policy.task_spawn
( TestTaskTeamValue( policy , result , begin - 1 )
, Kokkos::TaskTeam );
assert( ! future.is_null() );
policy.respawn( this , future );
}
return ;
}
Kokkos::parallel_for( Kokkos::TeamThreadRange(member,begin,end)
, [&]( int i ) { result[i] = i + 1 ; }
);
if ( member.team_rank() == 0 ) {
final = result[nvalue] ;
}
Kokkos::memory_fence();
}
static void run( long n )
{
// const unsigned memory_capacity = 10000 ; // causes memory pool infinite loop
const unsigned memory_capacity = 100000 ;
policy_type root_policy( typename policy_type::memory_space()
, memory_capacity );
view_type root_result("result",n+1);
typename view_type::HostMirror
host_result = Kokkos::create_mirror_view( root_result );
future_type fv = root_policy.host_spawn
( TestTaskTeamValue( root_policy, root_result, n ) , Kokkos::TaskTeam );
Kokkos::wait( root_policy );
Kokkos::deep_copy( host_result , root_result );
if ( fv.get() != n + 1 ) {
std::cerr << "TestTaskTeamValue ERROR future = "
<< fv.get() << " != " << n + 1 << std::endl ;
}
for ( long i = 0 ; i <= n ; ++i ) {
const long answer = i + 1 ;
if ( host_result(i) != answer ) {
std::cerr << "TestTaskTeamValue ERROR result(" << i << ") = "
<< host_result(i) << " != " << answer << std::endl ;
}
}
}
};
} // namespace TestTaskPolicy
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
namespace TestTaskPolicy {
template< class ExecSpace >
struct FibChild {
typedef long value_type ;
Kokkos::Experimental::TaskPolicy<ExecSpace> policy ;
Kokkos::Experimental::Future<long,ExecSpace> fib_1 ;
Kokkos::Experimental::Future<long,ExecSpace> fib_2 ;
const value_type n ;
int has_nested ;
KOKKOS_INLINE_FUNCTION
FibChild( const Kokkos::Experimental::TaskPolicy<ExecSpace> & arg_policy
, const value_type arg_n )
: policy(arg_policy)
, fib_1() , fib_2()
, n( arg_n ), has_nested(0) {}
KOKKOS_INLINE_FUNCTION
void apply( value_type & result )
{
typedef Kokkos::Experimental::Future<long,ExecSpace> future_type ;
if ( n < 2 ) {
has_nested = -1 ;
result = n ;
}
else {
if ( has_nested == 0 ) {
// Spawn new children and respawn myself to sum their results:
// Spawn lower value at higher priority as it has a shorter
// path to completion.
if ( fib_2.is_null() ) {
fib_2 = policy.task_create( FibChild(policy,n-2) );
}
if ( ! fib_2.is_null() && fib_1.is_null() ) {
fib_1 = policy.task_create( FibChild(policy,n-1) );
}
if ( ! fib_1.is_null() ) {
has_nested = 2 ;
policy.spawn( fib_2 , true /* high priority */ );
policy.spawn( fib_1 );
policy.add_dependence( this , fib_1 );
policy.add_dependence( this , fib_2 );
policy.respawn( this );
}
else {
// Release task memory before spawning the task,
// after spawning memory cannot be released.
fib_2 = future_type();
// Respawn when more memory is available
policy.respawn_needing_memory( this );
}
}
else if ( has_nested == 2 ) {
has_nested = -1 ;
result = fib_1.get() + fib_2.get();
if ( false ) {
printf("FibChild %ld = fib(%ld), task_count(%d)\n"
, long(n), long(result), policy.allocated_task_count());
}
}
else {
printf("FibChild(%ld) execution error\n",(long)n);
Kokkos::abort("FibChild execution error");
}
}
}
};
template< class ExecSpace >
struct FibChild2 {
typedef long value_type ;
Kokkos::Experimental::TaskPolicy<ExecSpace> policy ;
Kokkos::Experimental::Future<long,ExecSpace> fib_a ;
Kokkos::Experimental::Future<long,ExecSpace> fib_b ;
const value_type n ;
int has_nested ;
KOKKOS_INLINE_FUNCTION
FibChild2( const Kokkos::Experimental::TaskPolicy<ExecSpace> & arg_policy
, const value_type arg_n )
: policy(arg_policy)
, n( arg_n ), has_nested(0) {}
KOKKOS_INLINE_FUNCTION
void apply( value_type & result )
{
if ( 0 == has_nested ) {
if ( n < 2 ) {
has_nested = -1 ;
result = n ;
}
else if ( n < 4 ) {
// Spawn new children and respawn myself to sum their results:
// result = Fib(n-1) + Fib(n-2)
has_nested = 2 ;
// Spawn lower value at higher priority as it has a shorter
// path to completion.
policy.clear_dependence( this );
fib_a = policy.spawn( policy.task_create( FibChild2(policy,n-1) ) );
fib_b = policy.spawn( policy.task_create( FibChild2(policy,n-2) ) , true );
policy.add_dependence( this , fib_a );
policy.add_dependence( this , fib_b );
policy.respawn( this );
}
else {
// Spawn new children and respawn myself to sum their results:
// result = Fib(n-1) + Fib(n-2)
// result = ( Fib(n-2) + Fib(n-3) ) + ( Fib(n-3) + Fib(n-4) )
// result = ( ( Fib(n-3) + Fib(n-4) ) + Fib(n-3) ) + ( Fib(n-3) + Fib(n-4) )
// result = 3 * Fib(n-3) + 2 * Fib(n-4)
has_nested = 4 ;
// Spawn lower value at higher priority as it has a shorter
// path to completion.
policy.clear_dependence( this );
fib_a = policy.spawn( policy.task_create( FibChild2(policy,n-3) ) );
fib_b = policy.spawn( policy.task_create( FibChild2(policy,n-4) ) , true );
policy.add_dependence( this , fib_a );
policy.add_dependence( this , fib_b );
policy.respawn( this );
}
}
else if ( 2 == has_nested || 4 == has_nested ) {
result = ( has_nested == 2 ) ? fib_a.get() + fib_b.get()
: 3 * fib_a.get() + 2 * fib_b.get() ;
has_nested = -1 ;
}
else {
printf("FibChild2(%ld) execution error\n",(long)n);
Kokkos::abort("FibChild2 execution error");
}
}
};
template< class ExecSpace >
void test_fib( long n , const unsigned task_max_count = 4096 )
{
const unsigned task_max_size = 256 ;
const unsigned task_dependence = 4 ;
Kokkos::Experimental::TaskPolicy<ExecSpace>
policy( task_max_count
, task_max_size
, task_dependence );
Kokkos::Experimental::Future<long,ExecSpace> f =
policy.spawn( policy.proc_create( FibChild<ExecSpace>(policy,n) ) );
Kokkos::Experimental::wait( policy );
if ( f.get() != eval_fib(n) ) {
std::cout << "Fib(" << n << ") = " << f.get();
std::cout << " != " << eval_fib(n);
std::cout << std::endl ;
}
}
template< class ExecSpace >
void test_fib2( long n , const unsigned task_max_count = 1024 )
{
const unsigned task_max_size = 256 ;
const unsigned task_dependence = 4 ;
Kokkos::Experimental::TaskPolicy<ExecSpace>
policy( task_max_count
, task_max_size
, task_dependence );
Kokkos::Experimental::Future<long,ExecSpace> f =
policy.spawn( policy.proc_create( FibChild2<ExecSpace>(policy,n) ) );
Kokkos::Experimental::wait( policy );
if ( f.get() != eval_fib(n) ) {
std::cout << "Fib2(" << n << ") = " << f.get();
std::cout << " != " << eval_fib(n);
std::cout << std::endl ;
}
}
//----------------------------------------------------------------------------
template< class ExecSpace >
struct Norm2 {
typedef double value_type ;
const double * const m_x ;
Norm2( const double * x ) : m_x(x) {}
inline
void init( double & val ) const { val = 0 ; }
KOKKOS_INLINE_FUNCTION
void operator()( int i , double & val ) const { val += m_x[i] * m_x[i] ; }
void apply( double & dst ) const { dst = std::sqrt( dst ); }
};
template< class ExecSpace >
void test_norm2( const int n )
{
const unsigned task_max_count = 1024 ;
const unsigned task_max_size = 256 ;
const unsigned task_dependence = 4 ;
Kokkos::Experimental::TaskPolicy<ExecSpace>
policy( task_max_count
, task_max_size
, task_dependence );
double * const x = new double[n];
for ( int i = 0 ; i < n ; ++i ) x[i] = 1 ;
Kokkos::RangePolicy<ExecSpace> r(0,n);
Kokkos::Experimental::Future<double,ExecSpace> f =
Kokkos::Experimental::spawn_reduce( policy , r , Norm2<ExecSpace>(x) );
Kokkos::Experimental::wait( policy );
#if defined(PRINT)
std::cout << "Norm2: " << f.get() << std::endl ;
#endif
delete[] x ;
}
//----------------------------------------------------------------------------
template< class Space >
struct TaskDep {
typedef int value_type ;
typedef Kokkos::Experimental::TaskPolicy< Space > policy_type ;
const policy_type policy ;
const int input ;
TaskDep( const policy_type & arg_p , const int arg_i )
: policy( arg_p ), input( arg_i ) {}
KOKKOS_INLINE_FUNCTION
void apply( int & val )
{
val = input ;
const int num = policy.get_dependence( this );
for ( int i = 0 ; i < num ; ++i ) {
Kokkos::Experimental::Future<int,Space> f = policy.get_dependence( this , i );
val += f.get();
}
}
};
template< class Space >
void test_task_dep( const int n )
{
enum { NTEST = 64 };
const unsigned task_max_count = 1024 ;
const unsigned task_max_size = 64 ;
const unsigned task_dependence = 4 ;
Kokkos::Experimental::TaskPolicy<Space>
policy( task_max_count
, task_max_size
, task_dependence );
Kokkos::Experimental::Future<int,Space> f[ NTEST ];
for ( int i = 0 ; i < NTEST ; ++i ) {
// Create task in the "constructing" state with capacity for 'n+1' dependences
f[i] = policy.proc_create( TaskDep<Space>(policy,0) , n + 1 );
if ( f[i].get_task_state() != Kokkos::Experimental::TASK_STATE_CONSTRUCTING ) {
Kokkos::Impl::throw_runtime_exception("get_task_state() != Kokkos::Experimental::TASK_STATE_CONSTRUCTING");
}
// Only use 'n' dependences
for ( int j = 0 ; j < n ; ++j ) {
Kokkos::Experimental::Future<int,Space> nested =
policy.proc_create( TaskDep<Space>(policy,j+1) );
policy.spawn( nested );
// Add dependence to a "constructing" task
policy.add_dependence( f[i] , nested );
}
// Spawn task from the "constructing" to the "waiting" state
policy.spawn( f[i] );
}
const int answer = n % 2 ? n * ( ( n + 1 ) / 2 ) : ( n / 2 ) * ( n + 1 );
Kokkos::Experimental::wait( policy );
int error = 0 ;
for ( int i = 0 ; i < NTEST ; ++i ) {
if ( f[i].get_task_state() != Kokkos::Experimental::TASK_STATE_COMPLETE ) {
Kokkos::Impl::throw_runtime_exception("get_task_state() != Kokkos::Experimental::TASK_STATE_COMPLETE");
}
if ( answer != f[i].get() && 0 == error ) {
std::cout << "test_task_dep(" << n << ") ERROR at[" << i << "]"
<< " answer(" << answer << ") != result(" << f[i].get() << ")" << std::endl ;
}
}
}
//----------------------------------------------------------------------------
template< class ExecSpace >
struct TaskTeam {
enum { SPAN = 8 };
typedef void value_type ;
typedef Kokkos::Experimental::TaskPolicy<ExecSpace> policy_type ;
typedef Kokkos::Experimental::Future<void,ExecSpace> future_type ;
typedef Kokkos::View<long*,ExecSpace> view_type ;
policy_type policy ;
future_type future ;
view_type result ;
const long nvalue ;
KOKKOS_INLINE_FUNCTION
TaskTeam( const policy_type & arg_policy
, const view_type & arg_result
, const long arg_nvalue )
: policy(arg_policy)
, future()
, result( arg_result )
, nvalue( arg_nvalue )
{}
KOKKOS_INLINE_FUNCTION
void apply( const typename policy_type::member_type & member )
{
const long end = nvalue + 1 ;
const long begin = 0 < end - SPAN ? end - SPAN : 0 ;
if ( 0 < begin && future.get_task_state() == Kokkos::Experimental::TASK_STATE_NULL ) {
if ( member.team_rank() == 0 ) {
future = policy.spawn( policy.task_create_team( TaskTeam( policy , result , begin - 1 ) ) );
policy.clear_dependence( this );
policy.add_dependence( this , future );
policy.respawn( this );
}
return ;
}
Kokkos::parallel_for( Kokkos::TeamThreadRange(member,begin,end)
, [&]( int i ) { result[i] = i + 1 ; }
);
}
};
template< class ExecSpace >
struct TaskTeamValue {
enum { SPAN = 8 };
typedef long value_type ;
typedef Kokkos::Experimental::TaskPolicy<ExecSpace> policy_type ;
typedef Kokkos::Experimental::Future<value_type,ExecSpace> future_type ;
typedef Kokkos::View<long*,ExecSpace> view_type ;
policy_type policy ;
future_type future ;
view_type result ;
const long nvalue ;
KOKKOS_INLINE_FUNCTION
TaskTeamValue( const policy_type & arg_policy
, const view_type & arg_result
, const long arg_nvalue )
: policy(arg_policy)
, future()
, result( arg_result )
, nvalue( arg_nvalue )
{}
KOKKOS_INLINE_FUNCTION
void apply( const typename policy_type::member_type & member , value_type & final )
{
const long end = nvalue + 1 ;
const long begin = 0 < end - SPAN ? end - SPAN : 0 ;
if ( 0 < begin && future.is_null() ) {
if ( member.team_rank() == 0 ) {
future = policy.task_create_team( TaskTeamValue( policy , result , begin - 1 ) );
policy.spawn( future );
policy.add_dependence( this , future );
policy.respawn( this );
}
return ;
}
Kokkos::parallel_for( Kokkos::TeamThreadRange(member,begin,end)
, [&]( int i ) { result[i] = i + 1 ; }
);
if ( member.team_rank() == 0 ) {
final = result[nvalue] ;
}
Kokkos::memory_fence();
}
};
template< class ExecSpace >
void test_task_team( long n )
{
typedef TaskTeam< ExecSpace > task_type ;
typedef TaskTeamValue< ExecSpace > task_value_type ;
typedef typename task_type::view_type view_type ;
typedef typename task_type::policy_type policy_type ;
typedef typename task_type::future_type future_type ;
typedef typename task_value_type::future_type future_value_type ;
const unsigned task_max_count = 1024 ;
const unsigned task_max_size = 256 ;
const unsigned task_dependence = 4 ;
policy_type
policy( task_max_count
, task_max_size
, task_dependence );
view_type result("result",n+1);
typename view_type::HostMirror
host_result = Kokkos::create_mirror_view( result );
future_type f = policy.proc_create_team( task_type( policy , result , n ) );
ASSERT_FALSE( f.is_null() );
policy.spawn( f );
Kokkos::Experimental::wait( policy );
Kokkos::deep_copy( host_result , result );
for ( long i = 0 ; i <= n ; ++i ) {
const long answer = i + 1 ;
if ( host_result(i) != answer ) {
std::cerr << "test_task_team void ERROR result(" << i << ") = "
<< host_result(i) << " != " << answer << std::endl ;
}
}
future_value_type fv = policy.proc_create_team( task_value_type( policy , result , n ) );
ASSERT_FALSE( fv.is_null() );
policy.spawn( fv );
Kokkos::Experimental::wait( policy );
Kokkos::deep_copy( host_result , result );
if ( fv.get() != n + 1 ) {
std::cerr << "test_task_team value ERROR future = "
<< fv.get() << " != " << n + 1 << std::endl ;
}
for ( long i = 0 ; i <= n ; ++i ) {
const long answer = i + 1 ;
if ( host_result(i) != answer ) {
std::cerr << "test_task_team value ERROR result(" << i << ") = "
<< host_result(i) << " != " << answer << std::endl ;
}
}
}
//----------------------------------------------------------------------------
template< class ExecSpace >
struct TaskLatchAdd {
typedef void value_type ;
typedef Kokkos::Experimental::Future< Kokkos::Experimental::Latch , ExecSpace > future_type ;
future_type latch ;
volatile int * count ;
KOKKOS_INLINE_FUNCTION
TaskLatchAdd( const future_type & arg_latch
, volatile int * const arg_count )
: latch( arg_latch )
, count( arg_count )
{}
KOKKOS_INLINE_FUNCTION
void apply()
{
Kokkos::atomic_fetch_add( count , 1 );
latch.add(1);
}
};
template< class ExecSpace >
struct TaskLatchRun {
typedef void value_type ;
typedef Kokkos::Experimental::TaskPolicy< ExecSpace > policy_type ;
typedef Kokkos::Experimental::Future< Kokkos::Experimental::Latch , ExecSpace > future_type ;
policy_type policy ;
int total ;
volatile int count ;
KOKKOS_INLINE_FUNCTION
TaskLatchRun( const policy_type & arg_policy , const int arg_total )
: policy(arg_policy), total(arg_total), count(0) {}
KOKKOS_INLINE_FUNCTION
void apply()
{
if ( 0 == count && 0 < total ) {
future_type latch = policy.create_latch( total );
for ( int i = 0 ; i < total ; ++i ) {
auto f = policy.task_create( TaskLatchAdd<ExecSpace>(latch,&count) , 0 );
if ( f.is_null() ) {
Kokkos::abort("TaskLatchAdd allocation FAILED" );
}
if ( policy.spawn( f ).is_null() ) {
Kokkos::abort("TaskLatcAdd spawning FAILED" );
}
}
policy.add_dependence( this , latch );
policy.respawn( this );
}
else if ( count != total ) {
printf("TaskLatchRun FAILED %d != %d\n",count,total);
}
}
};
template< class ExecSpace >
void test_latch( int n )
{
typedef TaskLatchRun< ExecSpace > task_type ;
typedef typename task_type::policy_type policy_type ;
// Primary + latch + n * LatchAdd
//
// This test uses several two different block sizes for allocation from the
// memory pool, so the memory size requested must be big enough to cause two
// or more superblocks to be used. Currently, the superblock size in the
// task policy is 2^16, so make the minimum requested memory size greater
// than this.
const unsigned task_max_count = n + 2 < 256 ? 256 : n + 2;
const unsigned task_max_size = 256;
const unsigned task_dependence = 4 ;
policy_type
policy( task_max_count
, task_max_size
, task_dependence );
policy.spawn( policy.proc_create( TaskLatchRun<ExecSpace>(policy,n) ) );
wait( policy );
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
} // namespace TestTaskPolicy
#endif /* #if defined( KOKKOS_ENABLE_TASKPOLICY ) */
#endif /* #ifndef KOKKOS_UNITTEST_TASKPOLICY_HPP */
Event Timeline
Log In to Comment