Skip to content

Commit 057b122

Browse files
authored
fix behavior of nested arrays (#354)
* fix issue when nested arrays had inconsistent spaces, and child arrays were not moved because of the status of the outer arrays. This fix enforces the move of data regardless of outer array status.
1 parent 9c95439 commit 057b122

3 files changed

Lines changed: 256 additions & 8 deletions

File tree

src/ChaiBuffer.hpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -436,14 +436,7 @@ class ChaiBuffer
436436
if( m_pointerRecord == nullptr ||
437437
m_capacity == 0 ||
438438
chaiSpace == chai::NONE ) return;
439-
440-
chai::ExecutionSpace const prevSpace = m_pointerRecord->m_last_space;
441-
442-
if( prevSpace == chai::CPU && prevSpace != chaiSpace ) moveInnerData( space, size, touch );
443-
444-
move( space, touch );
445-
446-
if( prevSpace == chai::GPU && prevSpace != chaiSpace ) moveInnerData( space, size, touch );
439+
moveNestedImpl( space, size, touch );
447440
#else
448441
LVARRAY_ERROR_IF_NE( space, MemorySpace::host );
449442
LVARRAY_UNUSED_VARIABLE( size );
@@ -553,6 +546,24 @@ class ChaiBuffer
553546

554547
private:
555548

549+
template< typename U=T_non_const >
550+
std::enable_if_t< bufferManipulation::HasMemberFunction_move< U > >
551+
moveNestedImpl( MemorySpace const space, std::ptrdiff_t const size, bool const touch ) const
552+
{
553+
if( m_pointerRecord->m_last_space != chai::CPU )
554+
{
555+
move( MemorySpace::host, false );
556+
}
557+
558+
moveInnerData( space, size, touch );
559+
move( space, touch );
560+
}
561+
562+
template< typename U=T_non_const >
563+
std::enable_if_t< !bufferManipulation::HasMemberFunction_move< U > >
564+
moveNestedImpl( MemorySpace const space, std::ptrdiff_t const, bool const touch ) const
565+
{ move( space, touch ); }
566+
556567
/**
557568
* @tparam U A dummy parameter to enable SFINAE, do not specify.
558569
* @brief Move inner allocations to the memory space @p space.

unitTests/testArray1DOfArray1D.cpp

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,229 @@ TYPED_TEST( Array1DOfArray1DTest, emptyMove )
266266
this->emptyMove();
267267
}
268268

269+
#if defined(LVARRAY_USE_CHAI) && ( defined(LVARRAY_USE_CUDA) || defined(LVARRAY_USE_HIP) )
270+
271+
class Array1DOfArray1DOfArrayView2DTest : public ::testing::Test
272+
{
273+
public:
274+
using T = double;
275+
using IndexType = std::ptrdiff_t;
276+
277+
template< typename U >
278+
using Array1D = Array< U, 1, RAJA::PERM_I, IndexType, ChaiBuffer >;
279+
280+
template< typename U >
281+
using Array2D = Array< U, 2, RAJA::PERM_IJ, IndexType, ChaiBuffer >;
282+
283+
template< typename U >
284+
using ArrayView2D = ArrayView< U, 2, 1, IndexType, ChaiBuffer >;
285+
286+
using LeafOwners = Array1D< Array1D< Array2D< T > > >;
287+
using NestedViews = Array1D< Array1D< ArrayView2D< T const > > >;
288+
using NestedViewConst = typename NestedViews::NestedViewTypeConst;
289+
290+
static constexpr IndexType OUTER_SIZE = 3;
291+
292+
static constexpr IndexType innerSize( IndexType const i )
293+
{ return i + 1; }
294+
295+
static constexpr IndexType numRows( IndexType const i, IndexType const )
296+
{ return i + 1; }
297+
298+
static constexpr IndexType numCols( IndexType const, IndexType const j )
299+
{ return j + 2; }
300+
301+
static LVARRAY_HOST_DEVICE constexpr T initialValue( IndexType const i,
302+
IndexType const j,
303+
IndexType const r,
304+
IndexType const c )
305+
{ return T( 1000 * i + 100 * j + 10 * r + c ); }
306+
307+
static LVARRAY_HOST_DEVICE constexpr T deviceTouchedValue( IndexType const i,
308+
IndexType const j,
309+
IndexType const r,
310+
IndexType const c )
311+
{ return initialValue( i, j, r, c ) + T( 5000 ); }
312+
313+
static LVARRAY_HOST_DEVICE constexpr T hostTouchedValue( IndexType const i,
314+
IndexType const j,
315+
IndexType const r,
316+
IndexType const c )
317+
{ return initialValue( i, j, r, c ) + T( 9000 ); }
318+
319+
static void initialize( LeafOwners & owners, NestedViews & views )
320+
{
321+
owners.resize( OUTER_SIZE );
322+
views.resize( OUTER_SIZE );
323+
324+
for( IndexType i = 0; i < OUTER_SIZE; ++i )
325+
{
326+
owners[ i ].resize( innerSize( i ) );
327+
views[ i ].resize( innerSize( i ) );
328+
329+
for( IndexType j = 0; j < owners[ i ].size(); ++j )
330+
{
331+
owners[ i ][ j ].resize( numRows( i, j ), numCols( i, j ) );
332+
333+
for( IndexType r = 0; r < owners[ i ][ j ].size( 0 ); ++r )
334+
{
335+
for( IndexType c = 0; c < owners[ i ][ j ].size( 1 ); ++c )
336+
{
337+
owners[ i ][ j ]( r, c ) = initialValue( i, j, r, c );
338+
}
339+
}
340+
341+
views[ i ][ j ] = owners[ i ][ j ].toViewConst();
342+
}
343+
}
344+
}
345+
346+
static void touchLeavesOnDevice( LeafOwners & owners )
347+
{
348+
for( IndexType i = 0; i < owners.size(); ++i )
349+
{
350+
for( IndexType j = 0; j < owners[ i ].size(); ++j )
351+
{
352+
ArrayView2D< T > const leafView = owners[ i ][ j ].toView();
353+
forall< parallelDevicePolicy< 32 > >( leafView.size( 0 ), [leafView, i, j] LVARRAY_HOST_DEVICE ( IndexType const r )
354+
{
355+
for( IndexType c = 0; c < leafView.size( 1 ); ++c )
356+
{
357+
leafView( r, c ) = deviceTouchedValue( i, j, r, c );
358+
}
359+
} );
360+
}
361+
}
362+
}
363+
364+
static void touchLeavesOnHost( LeafOwners & owners )
365+
{
366+
for( IndexType i = 0; i < owners.size(); ++i )
367+
{
368+
for( IndexType j = 0; j < owners[ i ].size(); ++j )
369+
{
370+
ArrayView2D< T > const leafView = owners[ i ][ j ].toView();
371+
forall< serialPolicy >( leafView.size( 0 ), [leafView, i, j] LVARRAY_HOST_DEVICE ( IndexType const r )
372+
{
373+
for( IndexType c = 0; c < leafView.size( 1 ); ++c )
374+
{
375+
leafView( r, c ) = hostTouchedValue( i, j, r, c );
376+
}
377+
} );
378+
}
379+
}
380+
}
381+
382+
static void expectDeviceTouchedValuesInHostKernel( NestedViewConst const & nestedView )
383+
{
384+
forall< serialPolicy >( nestedView.size(), [nestedView] LVARRAY_HOST_DEVICE ( IndexType const i )
385+
{
386+
for( IndexType j = 0; j < nestedView[ i ].size(); ++j )
387+
{
388+
for( IndexType r = 0; r < nestedView[ i ][ j ].size( 0 ); ++r )
389+
{
390+
for( IndexType c = 0; c < nestedView[ i ][ j ].size( 1 ); ++c )
391+
{
392+
PORTABLE_EXPECT_EQ( nestedView[ i ][ j ]( r, c ), deviceTouchedValue( i, j, r, c ) );
393+
}
394+
}
395+
}
396+
} );
397+
}
398+
399+
static void expectDeviceTouchedValuesOnHost( NestedViewConst const & nestedView )
400+
{
401+
for( IndexType i = 0; i < nestedView.size(); ++i )
402+
{
403+
for( IndexType j = 0; j < nestedView[ i ].size(); ++j )
404+
{
405+
for( IndexType r = 0; r < nestedView[ i ][ j ].size( 0 ); ++r )
406+
{
407+
for( IndexType c = 0; c < nestedView[ i ][ j ].size( 1 ); ++c )
408+
{
409+
EXPECT_EQ( nestedView[ i ][ j ]( r, c ), deviceTouchedValue( i, j, r, c ) );
410+
}
411+
}
412+
}
413+
}
414+
}
415+
416+
static void warmOuterViewOnDevice( NestedViewConst const & nestedView )
417+
{
418+
forall< parallelDevicePolicy< 32 > >( nestedView.size(), [nestedView] LVARRAY_HOST_DEVICE ( IndexType const i )
419+
{
420+
for( IndexType j = 0; j < nestedView[ i ].size(); ++j )
421+
{
422+
for( IndexType r = 0; r < nestedView[ i ][ j ].size( 0 ); ++r )
423+
{
424+
for( IndexType c = 0; c < nestedView[ i ][ j ].size( 1 ); ++c )
425+
{
426+
PORTABLE_EXPECT_EQ( nestedView[ i ][ j ]( r, c ), initialValue( i, j, r, c ) );
427+
}
428+
}
429+
}
430+
} );
431+
}
432+
433+
static void expectHostTouchedValuesInDeviceKernel( NestedViewConst const & nestedView )
434+
{
435+
forall< parallelDevicePolicy< 32 > >( nestedView.size(), [nestedView] LVARRAY_HOST_DEVICE ( IndexType const i )
436+
{
437+
for( IndexType j = 0; j < nestedView[ i ].size(); ++j )
438+
{
439+
for( IndexType r = 0; r < nestedView[ i ][ j ].size( 0 ); ++r )
440+
{
441+
for( IndexType c = 0; c < nestedView[ i ][ j ].size( 1 ); ++c )
442+
{
443+
PORTABLE_EXPECT_EQ( nestedView[ i ][ j ]( r, c ), hostTouchedValue( i, j, r, c ) );
444+
}
445+
}
446+
}
447+
} );
448+
}
449+
};
450+
451+
TEST_F( Array1DOfArray1DOfArrayView2DTest, hostCaptureAfterDeviceTouch )
452+
{
453+
LeafOwners owners;
454+
NestedViews views;
455+
initialize( owners, views );
456+
457+
touchLeavesOnDevice( owners );
458+
459+
NestedViewConst const & nestedViewConst = views.toNestedViewConst();
460+
expectDeviceTouchedValuesInHostKernel( nestedViewConst );
461+
}
462+
463+
TEST_F( Array1DOfArray1DOfArrayView2DTest, explicitHostMoveAfterDeviceTouch )
464+
{
465+
LeafOwners owners;
466+
NestedViews views;
467+
initialize( owners, views );
468+
469+
touchLeavesOnDevice( owners );
470+
471+
NestedViewConst const & nestedViewConst = views.toNestedViewConst();
472+
nestedViewConst.move( MemorySpace::host );
473+
expectDeviceTouchedValuesOnHost( nestedViewConst );
474+
}
475+
476+
TEST_F( Array1DOfArray1DOfArrayView2DTest, deviceCaptureAfterHostTouchFollowingDeviceUse )
477+
{
478+
LeafOwners owners;
479+
NestedViews views;
480+
initialize( owners, views );
481+
482+
NestedViewConst const & nestedViewConst = views.toNestedViewConst();
483+
warmOuterViewOnDevice( nestedViewConst );
484+
485+
touchLeavesOnHost( owners );
486+
487+
expectHostTouchedValuesInDeviceKernel( nestedViewConst );
488+
}
489+
490+
#endif
491+
269492
} // namespace testing
270493
} // namespace LvArray
271494

unitTests/testUtils.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,20 @@ struct RAJAHelper< RAJA::policy::cuda::cuda_exec_explicit< X, Y, C, BLOCK_SIZE,
7474
static constexpr MemorySpace space = MemorySpace::cuda;
7575
};
7676

77+
#elif defined(LVARRAY_USE_HIP)
78+
79+
template< unsigned long THREADS_PER_BLOCK >
80+
using parallelDevicePolicy = RAJA::hip_exec< THREADS_PER_BLOCK >;
81+
82+
83+
template< typename X, typename Y, typename C, bool ASYNC >
84+
struct RAJAHelper< RAJA::policy::hip::hip_exec< X, Y, C, ASYNC > >
85+
{
86+
using ReducePolicy = RAJA::hip_reduce;
87+
using AtomicPolicy = RAJA::hip_atomic;
88+
static constexpr MemorySpace space = MemorySpace::hip;
89+
};
90+
7791
#endif
7892

7993
template< typename POLICY, typename INDEX_TYPE, typename LAMBDA >

0 commit comments

Comments
 (0)