Branch data Line data Source code
1 : : /** \file ReadHDF5Dataset.cpp
2 : : * \author Jason Kraftcheck
3 : : * \date 2010-07-09
4 : : */
5 : :
6 : : #include <assert.h>
7 : : #include <string.h>
8 : : #include <stdlib.h>
9 : : #include <iostream>
10 : : #include "moab/MOABConfig.h"
11 : : #include "ReadHDF5Dataset.hpp"
12 : :
13 : : #include "moab_mpe.h"
14 : :
15 : : #include <H5Dpublic.h>
16 : : #include <H5Tpublic.h>
17 : : #include <H5Ppublic.h>
18 : : #include <H5Spublic.h>
19 : : #ifdef MOAB_HAVE_HDF5_PARALLEL
20 : : #include <H5FDmpi.h>
21 : : #include <H5FDmpio.h>
22 : : #endif
23 : :
24 : : #define HDF5_16API ( H5_VERS_MAJOR < 2 && H5_VERS_MINOR < 8 )
25 : :
26 : : namespace moab
27 : : {
28 : :
29 : : // Selection of hyperslabs appears to be superlinear. Don't try to select
30 : : // more than a few thousand at a time or things start to get real slow.
31 : : const size_t DEFAULT_HYPERSLAB_SELECTION_LIMIT = 200;
32 : : size_t ReadHDF5Dataset::hyperslabSelectionLimit = DEFAULT_HYPERSLAB_SELECTION_LIMIT;
33 : 132 : void ReadHDF5Dataset::default_hyperslab_selection_limit()
34 : : {
35 : 132 : hyperslabSelectionLimit = DEFAULT_HYPERSLAB_SELECTION_LIMIT;
36 : 132 : }
37 : :
38 : : H5S_seloper_t ReadHDF5Dataset::hyperslabSelectOp = H5S_SELECT_OR;
39 : :
40 : : #ifdef MOAB_HAVE_LIBMPE
41 : : static std::pair< int, int > allocate_mpe_state( const char* name, const char* color )
42 : : {
43 : : std::pair< int, int > result;
44 : : result.first = MPE_Log_get_event_number();
45 : : result.second = MPE_Log_get_event_number();
46 : : MPE_Describe_state( result.first, result.second, name, color );
47 : : return result;
48 : : }
49 : : #else
50 : 42 : static std::pair< int, int > allocate_mpe_state( const char*, const char* )
51 : : {
52 : 42 : return std::pair< int, int >();
53 : : }
54 : : #endif
55 : :
56 : : bool ReadHDF5Dataset::haveMPEEvents = false;
57 : : std::pair< int, int > ReadHDF5Dataset::mpeReadEvent;
58 : : std::pair< int, int > ReadHDF5Dataset::mpeReduceEvent;
59 : :
60 : 0 : ReadHDF5Dataset::ReadHDF5Dataset( const char* debug_desc, bool parallel, const Comm* communicator )
61 : : : closeDataSet( false ), dataSet( -1 ), dataSpace( -1 ), dataType( -1 ), fileType( -1 ), ioProp( H5P_DEFAULT ),
62 : : dataSpaceRank( 0 ), rowsInTable( 0 ), doConversion( false ), nativeParallel( parallel ), readCount( 0 ),
63 [ # # ][ # # ]: 0 : bufferSize( 0 ), mpiComm( communicator ), mpeDesc( debug_desc )
[ # # ]
64 : : {
65 [ # # ]: 0 : if( !haveMPEEvents )
66 : : {
67 : 0 : haveMPEEvents = true;
68 [ # # ]: 0 : mpeReadEvent = allocate_mpe_state( "ReadHDF5Dataset::read", "yellow" );
69 [ # # ]: 0 : mpeReduceEvent = allocate_mpe_state( "ReadHDF5Dataset::all_reduce", "yellow" );
70 : : }
71 : :
72 : : #ifndef MOAB_HAVE_HDF5_PARALLEL
73 [ # # ][ # # ]: 0 : if( nativeParallel ) throw Exception( __LINE__ );
74 : : #else
75 : : if( nativeParallel && !mpiComm ) throw Exception( __LINE__ );
76 : :
77 : : if( mpiComm )
78 : : {
79 : : ioProp = H5Pcreate( H5P_DATASET_XFER );
80 : : H5Pset_dxpl_mpio( ioProp, H5FD_MPIO_COLLECTIVE );
81 : : }
82 : : #endif
83 : 0 : }
84 : :
85 : 1037 : ReadHDF5Dataset::ReadHDF5Dataset( const char* debug_desc, hid_t data_set_handle, bool parallel,
86 : : const Comm* communicator, bool close_data_set )
87 : : : closeDataSet( close_data_set ), dataSet( data_set_handle ), dataSpace( -1 ), dataType( -1 ), fileType( -1 ),
88 : : ioProp( H5P_DEFAULT ), dataSpaceRank( 0 ), rowsInTable( 0 ), doConversion( false ), nativeParallel( parallel ),
89 [ + - ][ + - ]: 1037 : readCount( 0 ), bufferSize( 0 ), mpiComm( communicator ), mpeDesc( debug_desc )
[ + - ]
90 : : {
91 [ + + ]: 1037 : if( !haveMPEEvents )
92 : : {
93 : 21 : haveMPEEvents = true;
94 [ + - ]: 21 : mpeReadEvent = allocate_mpe_state( "ReadHDF5Dataset::read", "yellow" );
95 [ + - ]: 21 : mpeReduceEvent = allocate_mpe_state( "ReadHDF5Dataset::all_reduce", "yellow" );
96 : : }
97 : :
98 [ + - ]: 1037 : init( data_set_handle, close_data_set );
99 : :
100 : : #ifndef MOAB_HAVE_HDF5_PARALLEL
101 [ - + ][ # # ]: 1037 : if( nativeParallel ) throw Exception( __LINE__ );
102 : : #else
103 : : if( nativeParallel && !mpiComm ) throw Exception( __LINE__ );
104 : :
105 : : if( mpiComm )
106 : : {
107 : : ioProp = H5Pcreate( H5P_DATASET_XFER );
108 : : H5Pset_dxpl_mpio( ioProp, H5FD_MPIO_COLLECTIVE );
109 : : }
110 : : #endif
111 : 1037 : }
112 : :
113 : 1037 : void ReadHDF5Dataset::init( hid_t data_set_handle, bool close_data_set )
114 : : {
115 : 1037 : closeDataSet = close_data_set;
116 : 1037 : dataSet = data_set_handle;
117 : :
118 : 1037 : fileType = H5Dget_type( data_set_handle );
119 [ - + ][ # # ]: 1037 : if( fileType < 0 ) throw Exception( __LINE__ );
120 : :
121 : 1037 : dataSpace = H5Dget_space( dataSet );
122 [ - + ][ # # ]: 1037 : if( dataSpace < 0 ) throw Exception( __LINE__ );
123 : :
124 : 1037 : dataSpaceRank = H5Sget_simple_extent_dims( dataSpace, dataSetCount, dataSetOffset );
125 [ - + ][ # # ]: 1037 : if( dataSpaceRank < 0 ) throw Exception( __LINE__ );
126 : 1037 : rowsInTable = dataSetCount[0];
127 : :
128 [ + + ]: 2244 : for( int i = 0; i < dataSpaceRank; ++i )
129 : 1207 : dataSetOffset[i] = 0;
130 : :
131 : 1037 : currOffset = rangeEnd = internalRange.end();
132 : 1037 : }
133 : :
134 : 86 : unsigned ReadHDF5Dataset::columns() const
135 : : {
136 [ + + ]: 86 : if( dataSpaceRank == 1 )
137 : 69 : return 1;
138 [ + - ]: 17 : else if( dataSpaceRank == 2 )
139 : 17 : return dataSetCount[1];
140 : :
141 [ # # ]: 86 : throw Exception( __LINE__ );
142 : : }
143 : :
144 : 0 : void ReadHDF5Dataset::set_column( unsigned column )
145 : : {
146 [ # # ][ # # ]: 0 : if( dataSpaceRank != 2 || column >= dataSetCount[1] ) throw Exception( __LINE__ );
[ # # ]
147 : 0 : dataSetCount[1] = 1;
148 : 0 : dataSetOffset[1] = column;
149 : 0 : }
150 : :
151 : 1037 : Range::const_iterator ReadHDF5Dataset::next_end( Range::const_iterator iter )
152 : : {
153 : 1037 : size_t slabs_remaining = hyperslabSelectionLimit;
154 : 1037 : size_t avail = bufferSize;
155 [ + + ][ + - ]: 2074 : while( iter != rangeEnd && slabs_remaining )
[ + + ]
156 : : {
157 [ + - ][ + - ]: 1037 : size_t count = *( iter.end_of_block() ) - *iter + 1;
158 [ - + ]: 1037 : if( count >= avail )
159 : : {
160 : 0 : iter += avail;
161 : 0 : break;
162 : : }
163 : :
164 : 1037 : avail -= count;
165 : 1037 : iter += count;
166 : 1037 : --slabs_remaining;
167 : : }
168 : 1037 : return iter;
169 : : }
170 : :
171 : 1037 : void ReadHDF5Dataset::set_file_ids( const Range& file_ids, EntityHandle start_id, hsize_t row_count, hid_t data_type )
172 : : {
173 : 1037 : startID = start_id;
174 : 1037 : currOffset = file_ids.begin();
175 : 1037 : rangeEnd = file_ids.end();
176 : 1037 : readCount = 0;
177 : 1037 : bufferSize = row_count;
178 : :
179 : : // if a) user specified buffer size and b) we're doing a true
180 : : // parallel partial read and c) we're doing collective I/O, then
181 : : // we need to know the maximum number of reads that will be done.
182 : : #ifdef MOAB_HAVE_HDF5_PARALLEL
183 : : if( nativeParallel )
184 : : {
185 : : Range::const_iterator iter = currOffset;
186 : : while( iter != rangeEnd )
187 : : {
188 : : ++readCount;
189 : : iter = next_end( iter );
190 : : }
191 : :
192 : : MPE_Log_event( mpeReduceEvent.first, (int)readCount, mpeDesc.c_str() );
193 : : unsigned long recv = readCount, send = readCount;
194 : : MPI_Allreduce( &send, &recv, 1, MPI_UNSIGNED_LONG, MPI_MAX, *mpiComm );
195 : : readCount = recv;
196 : : MPE_Log_event( mpeReduceEvent.second, (int)readCount, mpeDesc.c_str() );
197 : : }
198 : : #endif
199 : :
200 : 1037 : dataType = data_type;
201 : 1037 : htri_t equal = H5Tequal( fileType, dataType );
202 [ - + ][ # # ]: 1037 : if( equal < 0 ) throw Exception( __LINE__ );
203 : 1037 : doConversion = !equal;
204 : :
205 : : // We always read in the format of the file to avoid stupind HDF5
206 : : // library behavior when reading in parallel. We call H5Tconvert
207 : : // ourselves to do the data conversion. If the type we're reading
208 : : // from the file is larger than the type we want in memory, then
209 : : // we need to reduce num_rows so that we can read the larger type
210 : : // from the file into the passed buffer mean to accomodate num_rows
211 : : // of values of the smaller in-memory type.
212 [ + + ]: 1037 : if( doConversion )
213 : : {
214 : : size_t mem_size, file_size;
215 : 86 : mem_size = H5Tget_size( dataType );
216 : 86 : file_size = H5Tget_size( fileType );
217 [ - + ]: 86 : if( file_size > mem_size ) bufferSize = bufferSize * mem_size / file_size;
218 : : }
219 : 1037 : }
220 : :
221 : 235 : void ReadHDF5Dataset::set_all_file_ids( hsize_t row_count, hid_t data_type )
222 : : {
223 : 235 : internalRange.clear();
224 : 235 : internalRange.insert( (EntityHandle)1, ( EntityHandle )( rowsInTable ) );
225 : 235 : set_file_ids( internalRange, 1, row_count, data_type );
226 : 235 : }
227 : :
228 : 2074 : ReadHDF5Dataset::~ReadHDF5Dataset()
229 : : {
230 [ + - ]: 1037 : if( fileType >= 0 ) H5Tclose( fileType );
231 [ + - ]: 1037 : if( dataSpace >= 0 ) H5Sclose( dataSpace );
232 [ + + ][ + - ]: 1037 : if( closeDataSet && dataSet >= 0 ) H5Dclose( dataSet );
233 : 1037 : dataSpace = dataSet = -1;
234 [ - + ]: 1037 : if( ioProp != H5P_DEFAULT ) H5Pclose( ioProp );
235 : 1037 : }
236 : :
237 : 1037 : void ReadHDF5Dataset::read( void* buffer, size_t& rows_read )
238 : : {
239 : : herr_t err;
240 : 1037 : rows_read = 0;
241 : :
242 [ + - ][ + - ]: 1037 : MPE_Log_event( mpeReadEvent.first, (int)readCount, mpeDesc.c_str() );
[ + - ]
243 [ + - ]: 1037 : if( currOffset != rangeEnd )
244 : : {
245 : :
246 : : // Build H5S hyperslab selection describing the portions of the
247 : : // data set to read
248 : 1037 : H5S_seloper_t sop = H5S_SELECT_SET;
249 [ + - ]: 1037 : Range::iterator new_end = next_end( currOffset );
250 [ + - ][ + + ]: 2074 : while( currOffset != new_end )
251 : : {
252 [ + - ][ + - ]: 1037 : size_t count = *( currOffset.end_of_block() ) - *currOffset + 1;
[ + - ]
253 [ + - ][ - + ]: 1037 : if( new_end != rangeEnd && *currOffset + count > *new_end ) { count = *new_end - *currOffset; }
[ # # ][ # # ]
[ # # ][ - + ]
[ # # ][ # # ]
254 : 1037 : rows_read += count;
255 : :
256 [ + - ]: 1037 : dataSetOffset[0] = *currOffset - startID;
257 : 1037 : dataSetCount[0] = count;
258 [ + - ]: 1037 : err = H5Sselect_hyperslab( dataSpace, sop, dataSetOffset, NULL, dataSetCount, 0 );
259 [ - + ][ # # ]: 1037 : if( err < 0 ) throw Exception( __LINE__ );
260 : 1037 : sop = hyperslabSelectOp; // subsequent calls to select_hyperslab append
261 : :
262 [ + - ]: 1037 : currOffset += count;
263 : : }
264 : :
265 : : // Create a data space describing the memory in which to read the data
266 : 1037 : dataSetCount[0] = rows_read;
267 [ + - ]: 1037 : hid_t mem_id = H5Screate_simple( dataSpaceRank, dataSetCount, NULL );
268 [ - + ][ # # ]: 1037 : if( mem_id < 0 ) throw Exception( __LINE__ );
269 : :
270 : : // Do the actual read
271 [ + - ]: 1037 : err = H5Dread( dataSet, fileType, mem_id, dataSpace, ioProp, buffer );
272 [ + - ]: 1037 : H5Sclose( mem_id );
273 [ - + ][ # # ]: 1037 : if( err < 0 ) throw Exception( __LINE__ );
274 : :
275 [ - + ]: 1037 : if( readCount ) --readCount;
276 : :
277 [ + + ]: 1037 : if( doConversion )
278 : : {
279 [ + - ][ + - ]: 86 : err = H5Tconvert( fileType, dataType, rows_read * columns(), buffer, 0, H5P_DEFAULT );
280 [ - + ][ # # ]: 1037 : if( err < 0 ) throw Exception( __LINE__ );
281 : : }
282 : : }
283 [ # # ]: 0 : else if( readCount )
284 : : {
285 : 0 : null_read();
286 : 0 : --readCount;
287 : : }
288 [ + - ][ + - ]: 1037 : MPE_Log_event( mpeReadEvent.second, (int)readCount, mpeDesc.c_str() );
[ + - ]
289 : 1037 : }
290 : :
291 : 0 : void ReadHDF5Dataset::null_read()
292 : : {
293 : : herr_t err;
294 [ # # ]: 0 : err = H5Sselect_none( dataSpace );
295 [ # # ][ # # ]: 0 : if( err < 0 ) throw Exception( __LINE__ );
296 : :
297 : : //#if HDF5_16API
298 : 0 : hsize_t one = 1;
299 [ # # ]: 0 : hid_t mem_id = H5Screate_simple( 1, &one, NULL );
300 [ # # ][ # # ]: 0 : if( mem_id < 0 ) throw Exception( __LINE__ );
301 [ # # ]: 0 : err = H5Sselect_none( mem_id );
302 [ # # ]: 0 : if( err < 0 )
303 : : {
304 [ # # ]: 0 : H5Sclose( mem_id );
305 [ # # ]: 0 : throw Exception( __LINE__ );
306 : : }
307 : : //#else
308 : : // hid_t mem_id = H5Screate(H5S_NULL);
309 : : // if (mem_id < 0)
310 : : // throw Exception(__LINE__);
311 : : //#endif
312 : :
313 [ # # ]: 0 : err = H5Dread( dataSet, fileType, mem_id, dataSpace, ioProp, 0 );
314 [ # # ]: 0 : H5Sclose( mem_id );
315 [ # # ][ # # ]: 0 : if( err < 0 ) throw Exception( __LINE__ );
316 : 0 : }
317 : :
318 [ + - ][ + - ]: 228 : } // namespace moab
|