From ad01b6e3144843ccb16ac99bd12fd1ab1fc7a7b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Oberhuber?= <oberhuber.tomas@gmail.com> Date: Thu, 7 Mar 2019 21:41:06 +0100 Subject: [PATCH] Added type conversion to File read and write. --- src/TNL/File.hpp | 145 +++++++++++++++++++++++++++------------ src/UnitTests/FileTest.h | 85 +++++++++++++++++++++++ 2 files changed, 186 insertions(+), 44 deletions(-) diff --git a/src/TNL/File.hpp b/src/TNL/File.hpp index bbff0ab960..37ca5ef2db 100644 --- a/src/TNL/File.hpp +++ b/src/TNL/File.hpp @@ -88,7 +88,7 @@ bool File::read( Type* buffer, std::streamsize elements ) if( ! elements ) return true; - return read_impl< Type, Device >( buffer, elements ); + return read_impl< Type, Device, SourceType >( buffer, elements ); } // Host @@ -150,7 +150,7 @@ bool File::read_impl( Type* buffer, std::streamsize elements ) else { const std::streamsize cast_buffer_size = std::min( TransferBufferSize / (std::streamsize) sizeof(SourceType), elements ); - using BaseType = typename std::remove_cv< SorceType >::type; + using BaseType = typename std::remove_cv< SourceType >::type; std::unique_ptr< BaseType[] > cast_buffer{ new BaseType[ cast_buffer_size ] }; while( readElements < elements ) @@ -186,32 +186,40 @@ bool File::read_impl( Type* buffer, std::streamsize elements ) std::unique_ptr< BaseType[] > host_buffer{ new BaseType[ host_buffer_size ] }; std::streamsize readElements = 0; - while( readElements < elements ) + if( std::is_same< Type, SourceType >::value ) { - const std::streamsize transfer = std::min( elements - readElements, host_buffer_size ); - file.read( reinterpret_cast<char*>(host_buffer.get()), sizeof(Type) * transfer ); - - Devices::MICHider<Type> device_buff; - device_buff.pointer=buffer; - #pragma offload target(mic) in(device_buff,readElements) in(host_buffer:length(transfer)) + while( readElements < elements ) { - /* - for(int i=0;i<transfer;i++) - device_buff.pointer[readElements+i]=host_buffer[i]; - */ - memcpy(&(device_buff.pointer[readElements]), host_buffer.get(), transfer*sizeof(Type) ); - } + const std::streamsize transfer = std::min( elements - readElements, host_buffer_size ); + file.read( reinterpret_cast<char*>(host_buffer.get()), sizeof(Type) * transfer ); + + Devices::MICHider<Type> device_buff; + device_buff.pointer=buffer; + #pragma offload target(mic) in(device_buff,readElements) in(host_buffer:length(transfer)) + { + /* + for(int i=0;i<transfer;i++) + device_buff.pointer[readElements+i]=host_buffer[i]; + */ + memcpy(&(device_buff.pointer[readElements]), host_buffer.get(), transfer*sizeof(Type) ); + } - readElements += transfer; + readElements += transfer; + } + free( host_buffer ); + } + else + { + std::cerr << "Type conversion during loading is not implemented for MIC." << std::endl; + abort(); } - free( host_buffer ); return true; #else throw Exceptions::MICSupportMissing(); #endif } -template< class Type, typename Device, typename TargeType > +template< class Type, typename Device, typename TargetType > bool File::write( const Type* buffer, std::streamsize elements ) { TNL_ASSERT_GE( elements, 0, "Number of elements to write must be non-negative." ); @@ -219,7 +227,7 @@ bool File::write( const Type* buffer, std::streamsize elements ) if( ! elements ) return true; - return write_impl< Type, Device >( buffer, elements ); + return write_impl< Type, Device, TargetType >( buffer, elements ); } // Host @@ -229,7 +237,24 @@ template< typename Type, typename > bool File::write_impl( const Type* buffer, std::streamsize elements ) { - file.write( reinterpret_cast<const char*>(buffer), sizeof(Type) * elements ); + if( std::is_same< Type, TargetType >::value ) + file.write( reinterpret_cast<const char*>(buffer), sizeof(Type) * elements ); + else + { + const std::streamsize cast_buffer_size = std::min( TransferBufferSize / (std::streamsize) sizeof(TargetType), elements ); + using BaseType = typename std::remove_cv< TargetType >::type; + std::unique_ptr< BaseType[] > cast_buffer{ new BaseType[ cast_buffer_size ] }; + std::streamsize writtenElements = 0; + while( writtenElements < elements ) + { + const std::streamsize transfer = std::min( elements - writtenElements, cast_buffer_size ); + for( std::streamsize i = 0; i < transfer; i++ ) + cast_buffer[ i ] = static_cast< TargetType >( buffer[ writtenElements ++ ] ); + file.write( reinterpret_cast<char*>(cast_buffer.get()), sizeof(TargetType) * transfer ); + writtenElements += transfer; + } + + } return true; } @@ -246,16 +271,40 @@ bool File::write_impl( const Type* buffer, std::streamsize elements ) std::unique_ptr< BaseType[] > host_buffer{ new BaseType[ host_buffer_size ] }; std::streamsize writtenElements = 0; - while( writtenElements < elements ) + if( std::is_same< Type, TargetType >::value ) + { + while( writtenElements < elements ) + { + const std::streamsize transfer = std::min( elements - writtenElements, host_buffer_size ); + cudaMemcpy( (void*) host_buffer.get(), + (void*) &buffer[ writtenElements ], + transfer * sizeof(Type), + cudaMemcpyDeviceToHost ); + TNL_CHECK_CUDA_DEVICE; + file.write( reinterpret_cast<const char*>(host_buffer.get()), sizeof(Type) * transfer ); + writtenElements += transfer; + } + } + else { - const std::streamsize transfer = std::min( elements - writtenElements, host_buffer_size ); - cudaMemcpy( (void*) host_buffer.get(), - (void*) &buffer[ writtenElements ], - transfer * sizeof(Type), - cudaMemcpyDeviceToHost ); - TNL_CHECK_CUDA_DEVICE; - file.write( reinterpret_cast<const char*>(host_buffer.get()), sizeof(Type) * transfer ); - writtenElements += transfer; + const std::streamsize cast_buffer_size = std::min( TransferBufferSize / (std::streamsize) sizeof(TargetType), elements ); + using BaseType = typename std::remove_cv< TargetType >::type; + std::unique_ptr< BaseType[] > cast_buffer{ new BaseType[ cast_buffer_size ] }; + + while( writtenElements < elements ) + { + const std::streamsize transfer = std::min( elements - writtenElements, host_buffer_size ); + cudaMemcpy( (void*) host_buffer.get(), + (void*) &buffer[ writtenElements ], + transfer * sizeof(Type), + cudaMemcpyDeviceToHost ); + TNL_CHECK_CUDA_DEVICE; + for( std::streamsize i = 0; i < transfer; i++ ) + cast_buffer[ i ] = static_cast< TargetType >( host_buffer[ i ] ); + + file.write( reinterpret_cast<const char*>(cast_buffer.get()), sizeof(TargetType) * transfer ); + writtenElements += transfer; + } } return true; #else @@ -276,24 +325,32 @@ bool File::write_impl( const Type* buffer, std::streamsize elements ) std::unique_ptr< BaseType[] > host_buffer{ new BaseType[ host_buffer_size ] }; std::streamsize writtenElements = 0; - while( this->writtenElements < elements ) + if( std::is_same< Type, TargetType >::value ) { - const std::streamsize transfer = std::min( elements - writtenElements, host_buffer_size ); - - Devices::MICHider<const Type> device_buff; - device_buff.pointer=buffer; - #pragma offload target(mic) in(device_buff,writtenElements) out(host_buffer:length(transfer)) + while( this->writtenElements < elements ) { - //THIS SHOULD WORK... BUT NOT WHY? - /*for(int i=0;i<transfer;i++) - host_buffer[i]=device_buff.pointer[writtenElements+i]; - */ - - memcpy(host_buffer.get(), &(device_buff.pointer[writtenElements]), transfer*sizeof(Type) ); + const std::streamsize transfer = std::min( elements - writtenElements, host_buffer_size ); + + Devices::MICHider<const Type> device_buff; + device_buff.pointer=buffer; + #pragma offload target(mic) in(device_buff,writtenElements) out(host_buffer:length(transfer)) + { + //THIS SHOULD WORK... BUT NOT WHY? + /*for(int i=0;i<transfer;i++) + host_buffer[i]=device_buff.pointer[writtenElements+i]; + */ + + memcpy(host_buffer.get(), &(device_buff.pointer[writtenElements]), transfer*sizeof(Type) ); + } + + file.write( reinterpret_cast<const char*>(host_buffer.get()), sizeof(Type) * transfer ); + writtenElements += transfer; } - - file.write( reinterpret_cast<const char*>(host_buffer.get()), sizeof(Type) * transfer ); - writtenElements += transfer; + } + else + { + std::cerr << "Type conversion during saving is not implemented for MIC." << std::endl; + abort(); } return true; #else diff --git a/src/UnitTests/FileTest.h b/src/UnitTests/FileTest.h index 4f15d6ac71..93616bb17a 100644 --- a/src/UnitTests/FileTest.h +++ b/src/UnitTests/FileTest.h @@ -50,6 +50,37 @@ TEST( FileTest, WriteAndRead ) EXPECT_EQ( std::remove( "test-file.tnl" ), 0 ); }; +TEST( FileTest, WriteAndReadWithConversion ) +{ + double doubleData[ 3 ] = { 3.1415926535897932384626433, + 2.7182818284590452353602874, + 1.6180339887498948482045868 }; + float floatData[ 3 ]; + int intData[ 3 ]; + File file; + file.open( "test-file.tnl", File::Mode::Out | File::Mode::Truncate ); + file.write< double, Devices::Host, float >( doubleData, 3 ); + file.close(); + + file.open( "test-file.tnl", File::Mode::In ); + file.read< float, Devices::Host, float >( floatData, 3 ); + file.close(); + + file.open( "test-file.tnl", File::Mode::In ); + file.read< int, Devices::Host, float >( intData, 3 ); + file.close(); + + EXPECT_NEAR( floatData[ 0 ], 3.14159, 0.0001 ); + EXPECT_NEAR( floatData[ 1 ], 2.71828, 0.0001 ); + EXPECT_NEAR( floatData[ 2 ], 1.61803, 0.0001 ); + + EXPECT_EQ( intData[ 0 ], 3 ); + EXPECT_EQ( intData[ 1 ], 2 ); + EXPECT_EQ( intData[ 2 ], 1 ); + + EXPECT_EQ( std::remove( "test-file.tnl" ), 0 ); +} + #ifdef HAVE_CUDA TEST( FileTest, WriteAndReadCUDA ) { @@ -123,6 +154,60 @@ TEST( FileTest, WriteAndReadCUDA ) EXPECT_EQ( std::remove( "test-file.tnl" ), 0 ); }; + +TEST( FileTest, WriteAndReadCUDAWithConversion ) +{ + const double constDoubleData[ 3 ] = { 3.1415926535897932384626433, + 2.7182818284590452353602874, + 1.6180339887498948482045868 }; + float floatData[ 3 ]; + int intData[ 3 ]; + + int* cudaIntData; + float* cudaFloatData; + const double* cudaConstDoubleData; + cudaMalloc( ( void** ) &cudaIntData, 3 * sizeof( int ) ); + cudaMalloc( ( void** ) &cudaFloatData, 3 * sizeof( float ) ); + cudaMalloc( ( void** ) &cudaConstDoubleData, 3 * sizeof( double ) ); + cudaMemcpy( (void*) cudaConstDoubleData, + &constDoubleData, + 3 * sizeof( double ), + cudaMemcpyHostToDevice ); + + File file; + file.open( String( "cuda-test-file.tnl" ), File::Mode::Out | File::Mode::Truncate ); + file.write< double, Devices::Cuda, float >( cudaConstDoubleData, 3 ); + file.close(); + + file.open( String( "cuda-test-file.tnl" ), File::Mode::In ); + file.read< float, Devices::Cuda, float >( cudaFloatData, 3 ); + file.close(); + + file.open( String( "cuda-test-file.tnl" ), File::Mode::In ); + file.read< int, Devices::Cuda, float >( cudaIntData, 3 ); + file.close(); + + cudaMemcpy( floatData, + cudaFloatData, + 3 * sizeof( float ), + cudaMemcpyDeviceToHost ); + cudaMemcpy( &intData, + cudaIntData, + 3* sizeof( int ), + cudaMemcpyDeviceToHost ); + + + EXPECT_NEAR( floatData[ 0 ], 3.14159, 0.0001 ); + EXPECT_NEAR( floatData[ 1 ], 2.71828, 0.0001 ); + EXPECT_NEAR( floatData[ 2 ], 1.61803, 0.0001 ); + + EXPECT_EQ( intData[ 0 ], 3 ); + EXPECT_EQ( intData[ 1 ], 2 ); + EXPECT_EQ( intData[ 2 ], 1 ); + + EXPECT_EQ( std::remove( "cuda-test-file.tnl" ), 0 ); +}; + #endif #endif -- GitLab