MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 /** \file ReadHDF5Dataset.cpp 00002 * \author Jason Kraftcheck 00003 * \date 2010-07-09 00004 */ 00005 00006 #include <cassert> 00007 #include <cstring> 00008 #include <cstdlib> 00009 #include <iostream> 00010 #include "moab/MOABConfig.h" 00011 #include "ReadHDF5Dataset.hpp" 00012 00013 #include "moab_mpe.h" 00014 00015 #include <H5Dpublic.h> 00016 #include <H5Tpublic.h> 00017 #include <H5Ppublic.h> 00018 #include <H5Spublic.h> 00019 #ifdef MOAB_HAVE_HDF5_PARALLEL 00020 #include <H5FDmpi.h> 00021 #include <H5FDmpio.h> 00022 #endif 00023 00024 #define HDF5_16API ( H5_VERS_MAJOR < 2 && H5_VERS_MINOR < 8 ) 00025 00026 namespace moab 00027 { 00028 00029 // Selection of hyperslabs appears to be superlinear. Don't try to select 00030 // more than a few thousand at a time or things start to get real slow. 00031 const size_t DEFAULT_HYPERSLAB_SELECTION_LIMIT = 200; 00032 size_t ReadHDF5Dataset::hyperslabSelectionLimit = DEFAULT_HYPERSLAB_SELECTION_LIMIT; 00033 void ReadHDF5Dataset::default_hyperslab_selection_limit() 00034 { 00035 hyperslabSelectionLimit = DEFAULT_HYPERSLAB_SELECTION_LIMIT; 00036 } 00037 00038 H5S_seloper_t ReadHDF5Dataset::hyperslabSelectOp = H5S_SELECT_OR; 00039 00040 #ifdef MOAB_HAVE_LIBMPE 00041 static std::pair< int, int > allocate_mpe_state( const char* name, const char* color ) 00042 { 00043 std::pair< int, int > result; 00044 result.first = MPE_Log_get_event_number(); 00045 result.second = MPE_Log_get_event_number(); 00046 MPE_Describe_state( result.first, result.second, name, color ); 00047 return result; 00048 } 00049 #else 00050 static std::pair< int, int > allocate_mpe_state( const char*, const char* ) 00051 { 00052 return std::pair< int, int >(); 00053 } 00054 #endif 00055 00056 bool ReadHDF5Dataset::haveMPEEvents = false; 00057 std::pair< int, int > ReadHDF5Dataset::mpeReadEvent; 00058 std::pair< int, int > ReadHDF5Dataset::mpeReduceEvent; 00059 00060 ReadHDF5Dataset::ReadHDF5Dataset( const char* debug_desc, bool parallel, const Comm* communicator ) 00061 : closeDataSet( false ), dataSet( -1 ), dataSpace( -1 ), dataType( -1 ), fileType( -1 ), ioProp( H5P_DEFAULT ), 00062 dataSpaceRank( 0 ), rowsInTable( 0 ), doConversion( false ), nativeParallel( parallel ), readCount( 0 ), 00063 bufferSize( 0 ), mpiComm( communicator ), mpeDesc( debug_desc ) 00064 { 00065 if( !haveMPEEvents ) 00066 { 00067 haveMPEEvents = true; 00068 mpeReadEvent = allocate_mpe_state( "ReadHDF5Dataset::read", "yellow" ); 00069 mpeReduceEvent = allocate_mpe_state( "ReadHDF5Dataset::all_reduce", "yellow" ); 00070 } 00071 00072 #ifndef MOAB_HAVE_HDF5_PARALLEL 00073 if( nativeParallel ) throw Exception( __LINE__ ); 00074 #else 00075 if( nativeParallel && !mpiComm ) throw Exception( __LINE__ ); 00076 00077 if( mpiComm ) 00078 { 00079 ioProp = H5Pcreate( H5P_DATASET_XFER ); 00080 H5Pset_dxpl_mpio( ioProp, H5FD_MPIO_COLLECTIVE ); 00081 } 00082 #endif 00083 } 00084 00085 ReadHDF5Dataset::ReadHDF5Dataset( const char* debug_desc, 00086 hid_t data_set_handle, 00087 bool parallel, 00088 const Comm* communicator, 00089 bool close_data_set ) 00090 : closeDataSet( close_data_set ), dataSet( data_set_handle ), dataSpace( -1 ), dataType( -1 ), fileType( -1 ), 00091 ioProp( H5P_DEFAULT ), dataSpaceRank( 0 ), rowsInTable( 0 ), doConversion( false ), nativeParallel( parallel ), 00092 readCount( 0 ), bufferSize( 0 ), mpiComm( communicator ), mpeDesc( debug_desc ) 00093 { 00094 if( !haveMPEEvents ) 00095 { 00096 haveMPEEvents = true; 00097 mpeReadEvent = allocate_mpe_state( "ReadHDF5Dataset::read", "yellow" ); 00098 mpeReduceEvent = allocate_mpe_state( "ReadHDF5Dataset::all_reduce", "yellow" ); 00099 } 00100 00101 init( data_set_handle, close_data_set ); 00102 00103 #ifndef MOAB_HAVE_HDF5_PARALLEL 00104 if( nativeParallel ) throw Exception( __LINE__ ); 00105 #else 00106 if( nativeParallel && !mpiComm ) throw Exception( __LINE__ ); 00107 00108 if( mpiComm ) 00109 { 00110 ioProp = H5Pcreate( H5P_DATASET_XFER ); 00111 H5Pset_dxpl_mpio( ioProp, H5FD_MPIO_COLLECTIVE ); 00112 } 00113 #endif 00114 } 00115 00116 void ReadHDF5Dataset::init( hid_t data_set_handle, bool close_data_set ) 00117 { 00118 closeDataSet = close_data_set; 00119 dataSet = data_set_handle; 00120 00121 fileType = H5Dget_type( data_set_handle ); 00122 if( fileType < 0 ) throw Exception( __LINE__ ); 00123 00124 dataSpace = H5Dget_space( dataSet ); 00125 if( dataSpace < 0 ) throw Exception( __LINE__ ); 00126 00127 dataSpaceRank = H5Sget_simple_extent_dims( dataSpace, dataSetCount, dataSetOffset ); 00128 if( dataSpaceRank < 0 ) throw Exception( __LINE__ ); 00129 rowsInTable = dataSetCount[0]; 00130 00131 for( int i = 0; i < dataSpaceRank; ++i ) 00132 dataSetOffset[i] = 0; 00133 00134 currOffset = rangeEnd = internalRange.end(); 00135 } 00136 00137 unsigned ReadHDF5Dataset::columns() const 00138 { 00139 if( dataSpaceRank == 1 ) 00140 return 1; 00141 else if( dataSpaceRank == 2 ) 00142 return dataSetCount[1]; 00143 00144 throw Exception( __LINE__ ); 00145 } 00146 00147 void ReadHDF5Dataset::set_column( unsigned column ) 00148 { 00149 if( dataSpaceRank != 2 || column >= dataSetCount[1] ) throw Exception( __LINE__ ); 00150 dataSetCount[1] = 1; 00151 dataSetOffset[1] = column; 00152 } 00153 00154 Range::const_iterator ReadHDF5Dataset::next_end( Range::const_iterator iter ) 00155 { 00156 size_t slabs_remaining = hyperslabSelectionLimit; 00157 size_t avail = bufferSize; 00158 while( iter != rangeEnd && slabs_remaining ) 00159 { 00160 size_t count = *( iter.end_of_block() ) - *iter + 1; 00161 if( count >= avail ) 00162 { 00163 iter += avail; 00164 break; 00165 } 00166 00167 avail -= count; 00168 iter += count; 00169 --slabs_remaining; 00170 } 00171 return iter; 00172 } 00173 00174 void ReadHDF5Dataset::set_file_ids( const Range& file_ids, EntityHandle start_id, hsize_t row_count, hid_t data_type ) 00175 { 00176 startID = start_id; 00177 currOffset = file_ids.begin(); 00178 rangeEnd = file_ids.end(); 00179 readCount = 0; 00180 bufferSize = row_count; 00181 00182 // if a) user specified buffer size and b) we're doing a true 00183 // parallel partial read and c) we're doing collective I/O, then 00184 // we need to know the maximum number of reads that will be done. 00185 #ifdef MOAB_HAVE_HDF5_PARALLEL 00186 if( nativeParallel ) 00187 { 00188 Range::const_iterator iter = currOffset; 00189 while( iter != rangeEnd ) 00190 { 00191 ++readCount; 00192 iter = next_end( iter ); 00193 } 00194 00195 MPE_Log_event( mpeReduceEvent.first, (int)readCount, mpeDesc.c_str() ); 00196 unsigned long recv = readCount, send = readCount; 00197 MPI_Allreduce( &send, &recv, 1, MPI_UNSIGNED_LONG, MPI_MAX, *mpiComm ); 00198 readCount = recv; 00199 MPE_Log_event( mpeReduceEvent.second, (int)readCount, mpeDesc.c_str() ); 00200 } 00201 #endif 00202 00203 dataType = data_type; 00204 htri_t equal = H5Tequal( fileType, dataType ); 00205 if( equal < 0 ) throw Exception( __LINE__ ); 00206 doConversion = !equal; 00207 00208 // We always read in the format of the file to avoid stupind HDF5 00209 // library behavior when reading in parallel. We call H5Tconvert 00210 // ourselves to do the data conversion. If the type we're reading 00211 // from the file is larger than the type we want in memory, then 00212 // we need to reduce num_rows so that we can read the larger type 00213 // from the file into the passed buffer mean to accomodate num_rows 00214 // of values of the smaller in-memory type. 00215 if( doConversion ) 00216 { 00217 size_t mem_size, file_size; 00218 mem_size = H5Tget_size( dataType ); 00219 file_size = H5Tget_size( fileType ); 00220 if( file_size > mem_size ) bufferSize = bufferSize * mem_size / file_size; 00221 } 00222 } 00223 00224 void ReadHDF5Dataset::set_all_file_ids( hsize_t row_count, hid_t data_type ) 00225 { 00226 internalRange.clear(); 00227 internalRange.insert( (EntityHandle)1, (EntityHandle)( rowsInTable ) ); 00228 set_file_ids( internalRange, 1, row_count, data_type ); 00229 } 00230 00231 ReadHDF5Dataset::~ReadHDF5Dataset() 00232 { 00233 if( fileType >= 0 ) H5Tclose( fileType ); 00234 if( dataSpace >= 0 ) H5Sclose( dataSpace ); 00235 if( closeDataSet && dataSet >= 0 ) H5Dclose( dataSet ); 00236 dataSpace = dataSet = -1; 00237 if( ioProp != H5P_DEFAULT ) H5Pclose( ioProp ); 00238 } 00239 00240 void ReadHDF5Dataset::read( void* buffer, size_t& rows_read ) 00241 { 00242 herr_t err; 00243 rows_read = 0; 00244 00245 MPE_Log_event( mpeReadEvent.first, (int)readCount, mpeDesc.c_str() ); 00246 if( currOffset != rangeEnd ) 00247 { 00248 00249 // Build H5S hyperslab selection describing the portions of the 00250 // data set to read 00251 H5S_seloper_t sop = H5S_SELECT_SET; 00252 Range::iterator new_end = next_end( currOffset ); 00253 while( currOffset != new_end ) 00254 { 00255 size_t count = *( currOffset.end_of_block() ) - *currOffset + 1; 00256 if( new_end != rangeEnd && *currOffset + count > *new_end ) 00257 { 00258 count = *new_end - *currOffset; 00259 } 00260 rows_read += count; 00261 00262 dataSetOffset[0] = *currOffset - startID; 00263 dataSetCount[0] = count; 00264 err = H5Sselect_hyperslab( dataSpace, sop, dataSetOffset, NULL, dataSetCount, 0 ); 00265 if( err < 0 ) throw Exception( __LINE__ ); 00266 sop = hyperslabSelectOp; // subsequent calls to select_hyperslab append 00267 00268 currOffset += count; 00269 } 00270 00271 // Create a data space describing the memory in which to read the data 00272 dataSetCount[0] = rows_read; 00273 hid_t mem_id = H5Screate_simple( dataSpaceRank, dataSetCount, NULL ); 00274 if( mem_id < 0 ) throw Exception( __LINE__ ); 00275 00276 // Do the actual read 00277 err = H5Dread( dataSet, fileType, mem_id, dataSpace, ioProp, buffer ); 00278 H5Sclose( mem_id ); 00279 if( err < 0 ) throw Exception( __LINE__ ); 00280 00281 if( readCount ) --readCount; 00282 00283 if( doConversion ) 00284 { 00285 err = H5Tconvert( fileType, dataType, rows_read * columns(), buffer, 0, H5P_DEFAULT ); 00286 if( err < 0 ) throw Exception( __LINE__ ); 00287 } 00288 } 00289 else if( readCount ) 00290 { 00291 null_read(); 00292 --readCount; 00293 } 00294 MPE_Log_event( mpeReadEvent.second, (int)readCount, mpeDesc.c_str() ); 00295 } 00296 00297 void ReadHDF5Dataset::null_read() 00298 { 00299 herr_t err; 00300 err = H5Sselect_none( dataSpace ); 00301 if( err < 0 ) throw Exception( __LINE__ ); 00302 00303 //#if HDF5_16API 00304 hsize_t one = 1; 00305 hid_t mem_id = H5Screate_simple( 1, &one, NULL ); 00306 if( mem_id < 0 ) throw Exception( __LINE__ ); 00307 err = H5Sselect_none( mem_id ); 00308 if( err < 0 ) 00309 { 00310 H5Sclose( mem_id ); 00311 throw Exception( __LINE__ ); 00312 } 00313 //#else 00314 // hid_t mem_id = H5Screate(H5S_NULL); 00315 // if (mem_id < 0) 00316 // throw Exception(__LINE__); 00317 //#endif 00318 00319 err = H5Dread( dataSet, fileType, mem_id, dataSpace, ioProp, 0 ); 00320 H5Sclose( mem_id ); 00321 if( err < 0 ) throw Exception( __LINE__ ); 00322 } 00323 00324 } // namespace moab