diff options
40 files changed, 4514 insertions, 1941 deletions
@@ -290,6 +290,8 @@ ./fortran/testpar/ptest.f90 ./fortran/testpar/hyper.f90 ./fortran/testpar/mdset.f90 +./fortran/testpar/ptest_F03.f90 +./fortran/testpar/multidsetrw_F03.f90 #------------------------------------------------------------------------------ # @@ -1016,6 +1018,7 @@ ./test/le_extlink2.h5 ./test/lheap.c ./test/links.c +./test/mdset.c ./test/mergemsg.h5 ./test/mf.c ./test/mount.c @@ -1244,6 +1247,7 @@ ./testpar/t_ph5basic.c ./testpar/t_pflush1.c ./testpar/t_pflush2.c +./testpar/t_pmulti_dset.c ./testpar/t_pread.c ./testpar/t_prop.c ./testpar/t_shapesame.c @@ -37,6 +37,7 @@ $Source = ""; "H5D_mpio_actual_io_mode_t" => "Di", "H5D_chunk_index_t" => "Dk", "H5D_layout_t" => "Dl", + "H5D_rw_multi_t" => "Dm", "H5D_mpio_no_collective_cause_t" => "Dn", "H5D_mpio_actual_chunk_opt_mode_t" => "Do", "H5D_space_status_t" => "Ds", diff --git a/fortran/src/H5Df.c b/fortran/src/H5Df.c index 588ea9f..f374c09 100644 --- a/fortran/src/H5Df.c +++ b/fortran/src/H5Df.c @@ -1315,3 +1315,70 @@ h5dvlen_reclaim_c(hid_t_f *type_id, hid_t_f *space_id, hid_t_f *plist_id, void * ret_value = 0; return ret_value; } + +/****if* H5FDmpio/h5dread_multi_c + * NAME + * h5dread_multi_c + * PURPOSE + * Calls H5Dread_multi + * + * INPUTS + * dxpl_id - dataset transfer property. + * count - the number of accessing datasets. + * OUTPUTS + * info - the array of dataset information and read buffer. + * + * RETURNS + * 0 on success, -1 on failure + * AUTHOR + * M. Scot Breitenfeld + * March 25, 2014 + * SOURCE +*/ +int_f +nh5dread_multi_c(hid_t_f *dxpl_id, size_t_f *count, H5D_rw_multi_t_f *info) +/******/ +{ + int ret_value = -1; + /* + * Call H5Dread_multi function. + */ + if( (H5Dread_multi((hid_t)*dxpl_id, (size_t)*count, info )) <0 ) + return ret_value; /* error occurred */ + + ret_value = 0; + return ret_value; +} + +/****if* H5FDmpio/h5dwrite_multi_c + * NAME + * h5dwrite_multi_c + * PURPOSE + * Calls H5Dwrite_multi + * + * INPUTS + * count - the number of accessing datasets. + * dxpl_id - dataset transfer property. + * Info - the array of dataset information and write buffer. + * + * RETURNS + * 0 on success, -1 on failure + * AUTHOR + * M. Scot Breitenfeld + * March 25, 2014 + * SOURCE +*/ +int_f +nh5dwrite_multi_c(hid_t_f *dxpl_id, size_t_f *count, H5D_rw_multi_t_f *info) +/******/ +{ + int ret_value = -1; + /* + * Call H5Dwrite_multi function. + */ + if( (H5Dwrite_multi((hid_t)*dxpl_id, (size_t)*count, info )) <0 ) + return ret_value; /* error occurred */ + + ret_value = 0; + return ret_value; +} diff --git a/fortran/src/H5f90proto.h b/fortran/src/H5f90proto.h index 46ef8ef..9ffae1e 100644 --- a/fortran/src/H5f90proto.h +++ b/fortran/src/H5f90proto.h @@ -23,6 +23,21 @@ H5_FCDLL void HD5packFstring(char *src, char *dest, size_t len); /* + * Storage struct used by H5Dread_multi and H5Dwrite_multi, + * interoperable with Fortran. + */ +typedef struct H5D_rw_multi_t_f { + hid_t dset_id; /* dstaset ID */ + hid_t dset_space_id; /* dataset selection dataspace ID */ + hid_t mem_type_id; /* memory datatype ID */ + hid_t mem_space_id; /* memory selection dataspace ID */ + union { + void *rbuf; /* pointer to read buffer */ + const void *wbuf; /* pointer to write buffer */ + } u; +} H5D_rw_multi_t_f; + +/* * Storage info struct used by H5O_info_t and H5F_info_t * interoperable with Fortran. */ @@ -131,6 +146,8 @@ H5_FCDLL int_f h5sextent_equal_c( hid_t_f * space1_id, hid_t_f *space2_id, hid_t /* * Functions from H5Df.c */ +#define nh5dread_multi_c H5_FC_FUNC_(h5dread_multi_c, H5DREAD_MULTI_C) +#define nh5dwrite_multi_c H5_FC_FUNC_(h5dwrite_multi_c, H5DWRITE_MULTI_C) H5_FCDLL int_f h5dcreate_c(hid_t_f *loc_id, _fcd name, int_f *namelen, hid_t_f *type_id, hid_t_f *space_id, hid_t_f *lcpl_id, hid_t_f *dcpl_id, hid_t_f *dapl_id, hid_t_f *dset_id); @@ -162,6 +179,8 @@ H5_FCDLL int_f h5dread_f_c( hid_t_f *dset_id , hid_t_f *mem_type_id, hid_t_f *m hid_t_f *file_space_id, hid_t_f *xfer_prp, void *buf); H5_FCDLL int_f h5dvlen_reclaim_c(hid_t_f *type_id , hid_t_f *space_id, hid_t_f *plist_id, void *buf); +H5_FCDLL int_f nh5dread_multi_c(hid_t_f *dxpl_id, size_t_f *count, H5D_rw_multi_t_f *info); +H5_FCDLL int_f nh5dwrite_multi_c(hid_t_f *dxpl_id, size_t_f *count, H5D_rw_multi_t_f *info); /* * Functions from H5Gf.c */ diff --git a/fortran/src/hdf5_fortrandll.def.in b/fortran/src/hdf5_fortrandll.def.in index 3a5a91f..08daacf 100644 --- a/fortran/src/hdf5_fortrandll.def.in +++ b/fortran/src/hdf5_fortrandll.def.in @@ -75,6 +75,8 @@ H5D_mp_H5DGET_ACCESS_PLIST_F H5D_mp_H5DWRITE_PTR H5D_mp_H5DREAD_PTR H5D_mp_H5DVLEN_RECLAIM_F +@H5_NOF03EXP@H5D_PROVISIONAL_mp_H5DREAD_MULTI_F +@H5_NOF03EXP@H5D_PROVISIONAL_mp_H5DWRITE_MULTI_F ; H5E H5E_mp_H5ECLEAR_F H5E_mp_H5EPRINT_F diff --git a/fortran/testpar/CMakeLists.txt b/fortran/testpar/CMakeLists.txt index 909cbaf..1c9c1f1 100644 --- a/fortran/testpar/CMakeLists.txt +++ b/fortran/testpar/CMakeLists.txt @@ -31,4 +31,24 @@ target_include_directories (parallel_test PRIVATE ${CMAKE_Fortran_MODULE_DIRECTO set_target_properties (parallel_test PROPERTIES LINKER_LANGUAGE Fortran) set_target_properties (parallel_test PROPERTIES FOLDER test/fortran) +#-- Adding test for parallel_test_F03 +if (HDF5_ENABLE_F2003) + add_executable (parallel_test_F03 + ptest_F03.f90 + multidsetrw_F03.f90 + ) + TARGET_NAMING (parallel_test_F03 ${LIB_TYPE}) + TARGET_FORTRAN_PROPERTIES (parallel_test_F03 " " " ") + target_link_libraries (parallel_test_F03 + ${HDF5_F90_TEST_LIB_TARGET} + ${HDF5_F90_LIB_TARGET} + ${HDF5_LIB_TARGET} + ) + if (WIN32 AND MSVC) + target_link_libraries (parallel_test_F03 "ws2_32.lib") + endif (WIN32 AND MSVC) + set_target_properties (parallel_test_F03 PROPERTIES LINKER_LANGUAGE Fortran) + set_target_properties (parallel_test_F03 PROPERTIES FOLDER test/fortran) +endif (HDF5_ENABLE_F2003) + include (CMakeTests.cmake) diff --git a/fortran/testpar/mdset.f90 b/fortran/testpar/mdset.f90 index 70d2939..0684de9 100644 --- a/fortran/testpar/mdset.f90 +++ b/fortran/testpar/mdset.f90 @@ -217,30 +217,30 @@ SUBROUTINE multiple_dset_write(length, do_collective, do_chunk, mpi_size, mpi_ra CALL check("h5pcreate_f", hdferror, nerrors) CALL h5pset_fapl_mpio_f(fapl_id, MPI_COMM_WORLD, MPI_INFO_NULL, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5pset_fapl_mpio_f", hdferror, nerrors) CALL h5fopen_f(filename, H5F_ACC_RDWR_F, file_id, hdferror, access_prp = fapl_id) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5fopen_f", hdferror, nerrors) CALL h5screate_simple_f(1, dims, fspace_id, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5screate_simple_f", hdferror, nerrors) CALL h5screate_simple_f(1, dims, mspace_id, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5screate_simple_f", hdferror, nerrors) !////////////////////////////////////////////////////////// ! select hyperslab in memory !////////////////////////////////////////////////////////// CALL h5sselect_hyperslab_f(mspace_id, H5S_SELECT_SET_F, start, counti, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5sselect_hyperslab_f", hdferror, nerrors) !////////////////////////////////////////////////////////// ! select hyperslab in the file !////////////////////////////////////////////////////////// CALL h5sselect_hyperslab_f(fspace_id, H5S_SELECT_SET_F, start, counti, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5sselect_hyperslab_f", hdferror, nerrors) !////////////////////////////////////////////////////////// ! create a property list for collective dataset read @@ -251,7 +251,7 @@ SUBROUTINE multiple_dset_write(length, do_collective, do_chunk, mpi_size, mpi_ra IF (do_collective) THEN CALL h5pset_dxpl_mpio_f(dxpl_id, H5FD_MPIO_COLLECTIVE_F, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5pset_dxpl_mpio_f", hdferror, nerrors) ENDIF !////////////////////////////////////////////////////////// @@ -265,11 +265,11 @@ SUBROUTINE multiple_dset_write(length, do_collective, do_chunk, mpi_size, mpi_ra ! create this dataset CALL h5dopen_f(file_id, dsetname, dset_id, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5dopen_f", hdferror, nerrors) ! read this dataset CALL h5dread_f(dset_id,H5T_NATIVE_INTEGER,rbuf,dims,hdferror,file_space_id=fspace_id,mem_space_id=mspace_id,xfer_prp=dxpl_id) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5dread_f", hdferror, nerrors) ! close this dataset CALL h5dclose_f(dset_id, hdferror) @@ -295,20 +295,19 @@ SUBROUTINE multiple_dset_write(length, do_collective, do_chunk, mpi_size, mpi_ra !////////////////////////////////////////////////////////// CALL h5pclose_f(fapl_id, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5pclose_f", hdferror, nerrors) CALL h5pclose_f(dxpl_id, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5pclose_f", hdferror, nerrors) CALL h5sclose_f(fspace_id, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5sclose_f", hdferror, nerrors) CALL h5sclose_f(mspace_id, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) + CALL check("h5sclose_f", hdferror, nerrors) CALL h5fclose_f(file_id, hdferror) - CALL check("h5pcreate_f", hdferror, nerrors) - + CALL check("h5fclose_f", hdferror, nerrors) DEALLOCATE(wbuf) DEALLOCATE(rbuf) diff --git a/fortran/testpar/multidsetrw_F03.f90 b/fortran/testpar/multidsetrw_F03.f90 new file mode 100644 index 0000000..177f94e --- /dev/null +++ b/fortran/testpar/multidsetrw_F03.f90 @@ -0,0 +1,206 @@ +! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +! Copyright by The HDF Group. * +! Copyright by the Board of Trustees of the University of Illinois. * +! All rights reserved. * +! * +! This file is part of HDF5. The full HDF5 copyright notice, including * +! terms governing use, modification, and redistribution, is contained in * +! the files COPYING and Copyright.html. COPYING can be found at the root * +! of the source code distribution tree; Copyright.html can be found at the * +! root level of an installed copy of the electronic HDF5 document set and * +! is linked from the top-level documents page. It can also be found at * +! http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * +! access to either file, you may request a copy from help@hdfgroup.org. * +! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +! +! writes/reads dataset by hyperslabs using multi-dataset routines, h5dread_multi and +! h5dwrite_multi +! + +SUBROUTINE pmultiple_dset_hyper_rw(do_collective, do_chunk, mpi_size, mpi_rank, nerrors) + + USE iso_c_binding + USE TH5_MISC + USE hdf5 + USE mpi + IMPLICIT NONE + + LOGICAL, INTENT(in) :: do_collective ! use collective IO + LOGICAL, INTENT(in) :: do_chunk ! use chunking + INTEGER, INTENT(in) :: mpi_size ! number of processes in the group of communicator + INTEGER, INTENT(in) :: mpi_rank ! rank of the calling process in the communicator + INTEGER, INTENT(inout) :: nerrors ! number of errors + CHARACTER(LEN=80):: dsetname ! Dataset name + TYPE(H5D_rw_multi_t), ALLOCATABLE, DIMENSION(:) :: info_md + INTEGER(hsize_t), DIMENSION(1:2) :: cdims ! chunk dimensions + + INTEGER(SIZE_T):: ndsets + INTEGER(HID_T) :: file_id ! File identifier + INTEGER(HID_T) :: filespace ! Dataspace identifier in file + INTEGER(HID_T) :: memspace ! Dataspace identifier in memory + INTEGER(HID_T) :: plist_id ! Property list identifier + INTEGER(HID_T) :: dcpl_id ! Dataset creation property list + INTEGER(HSIZE_T), DIMENSION(1:2) :: dimsf ! Dataset dimensions. + INTEGER(HSIZE_T), DIMENSION(1:2) :: dimsfi = (/5,8/) + + INTEGER(HSIZE_T), DIMENSION(1:2) :: count + INTEGER(HSSIZE_T), DIMENSION(1:2) :: offset + INTEGER, ALLOCATABLE, DIMENSION(:,:,:), TARGET :: DATA ! Data to write + INTEGER, ALLOCATABLE, DIMENSION(:,:,:), TARGET :: rDATA ! Data to write + INTEGER, PARAMETER :: rank = 2 ! Dataset rank + INTEGER :: i, j, k, istart + INTEGER :: error ! Error flags + + dimsf = (/5_hsize_t,INT(mpi_size, hsize_t)*8_hsize_t/) + ndsets = 5; + + ! + ! Setup file access property list with parallel I/O access. + ! + CALL h5pcreate_f(H5P_FILE_ACCESS_F, plist_id, error) + CALL check("h5pcreate_f", error, nerrors) + CALL h5pset_fapl_mpio_f(plist_id, MPI_COMM_WORLD, MPI_INFO_NULL, error) + CALL check("h5pset_fapl_mpio_f", error, nerrors) + ! + ! Create the file collectively. + ! + CALL h5fcreate_f("parf2.h5", H5F_ACC_TRUNC_F, file_id, error, access_prp = plist_id) + CALL check("h5fcreate_f", error, nerrors) + CALL h5pclose_f(plist_id, error) + CALL check("h5pclose_f", error, nerrors) + ! + ! Create the data space for the dataset. + ! + CALL h5screate_simple_f(rank, dimsf, filespace, error) + CALL check("h5screate_simple_f", error, nerrors) + ! + ! Each process defines dataset in memory and writes it to the hyperslab + ! in the file. + ! + count(1) = dimsf(1) + count(2) = dimsf(2)/mpi_size + offset(1) = 0 + offset(2) = mpi_rank * count(2) + CALL h5screate_simple_f(rank, count, memspace, error) + CALL check("h5screate_simple_f", error, nerrors) + + ! + ! Modify dataset creation properties to enable chunking + ! + + CALL h5pcreate_f(H5P_DATASET_CREATE_F, dcpl_id, error) + CALL check("h5pcreate_f", error, nerrors) + + IF (do_chunk) THEN + cdims(1) = dimsf(1) + cdims(2) = dimsf(2)/mpi_size/2 + CALL h5pset_chunk_f(dcpl_id, 2, cdims, error) + CALL check("h5pset_chunk_f", error, nerrors) + ENDIF + ! + ! Select hyperslab in the file. + ! + CALL h5sselect_hyperslab_f(filespace, H5S_SELECT_SET_F, offset, count, error) + CALL check("h5sselect_hyperslab_f", error, nerrors) + ! + ! Initialize data buffer + ! + ALLOCATE ( DATA(COUNT(1),COUNT(2), ndsets)) + ALLOCATE ( rdata(COUNT(1),COUNT(2), ndsets)) + + ALLOCATE(info_md(1:ndsets)) + + ! + ! Create property list for collective dataset write + ! + CALL h5pcreate_f(H5P_DATASET_XFER_F, plist_id, error) + CALL check("h5pcreate_f", error, nerrors) + IF(do_collective)THEN + CALL h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, error) + CALL check("h5pset_dxpl_mpio_f", error, nerrors) + ELSE + CALL h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_INDEPENDENT_F, error) + CALL check("h5pset_dxpl_mpio_f", error, nerrors) + ENDIF + + ! + ! Create the dataset with default properties. + ! + info_md(1:ndsets)%mem_type_id = H5T_NATIVE_INTEGER + info_md(1:ndsets)%mem_space_id = memspace + info_md(1:ndsets)%dset_space_id = filespace + + DO i = 1, ndsets + ! Create the data + DO k = 1, COUNT(1) + DO j = 1, COUNT(2) + istart = (k-1)*dimsf(2) + mpi_rank*COUNT(2) + DATA(k,j,i) = (istart + j)*10**(i-1) + ENDDO + ENDDO + ! Point to te data + info_md(i)%buf = C_LOC(DATA(1,1,i)) + + ! direct the output of the write statement to unit "dsetname" + WRITE(dsetname,'("dataset ",I0)') i + ! create the dataset + CALL h5dcreate_f(file_id, dsetname, H5T_NATIVE_INTEGER, filespace, info_md(i)%dset_id, error, dcpl_id) + CALL check("h5dcreate_f", error, nerrors) + ENDDO + ! + ! Write the dataset collectively. + ! + CALL h5dwrite_multi_f(plist_id, ndsets, info_md, error) + CALL check("h5dwrite_multi_f", error, nerrors) + + DO i = 1, ndsets + ! Point to the read buffer + info_md(i)%buf = C_LOC(rdata(1,1,i)) + ENDDO + + CALL H5Dread_multi_f(plist_id, ndsets, info_md, error) + CALL check("h5dread_multi_f", error, nerrors) + + DO i = 1, ndsets + ! Close all the datasets + CALL h5dclose_f(info_md(i)%dset_id, error) + CALL check("h5dclose_f", error, nerrors) + ENDDO + + ! check the data read and write buffers + DO i = 1, ndsets + ! Create the data + DO k = 1, COUNT(1) + DO j = 1, COUNT(2) + IF(rDATA(k,j,i).NE.DATA(k,j,i))THEN + nerrors = nerrors + 1 + ENDIF + ENDDO + ENDDO + ENDDO + ! + ! Deallocate data buffer. + ! + DEALLOCATE(data, rdata) + + ! + ! Close dataspaces. + ! + CALL h5sclose_f(filespace, error) + CALL check("h5sclose_f", error, nerrors) + CALL h5sclose_f(memspace, error) + CALL check("h5sclose_f", error, nerrors) + ! + ! Close the dataset and property list. + ! + CALL h5pclose_f(plist_id, error) + CALL check("h5pclose_f", error, nerrors) + + ! + ! Close the file. + ! + CALL h5fclose_f(file_id, error) + CALL check("h5fclose_f", error, nerrors) + +END SUBROUTINE pmultiple_dset_hyper_rw diff --git a/fortran/testpar/ptest_F03.f90 b/fortran/testpar/ptest_F03.f90 new file mode 100644 index 0000000..23bab8a --- /dev/null +++ b/fortran/testpar/ptest_F03.f90 @@ -0,0 +1,91 @@ +! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +! Copyright by The HDF Group. * +! Copyright by the Board of Trustees of the University of Illinois. * +! All rights reserved. * +! * +! This file is part of HDF5. The full HDF5 copyright notice, including * +! terms governing use, modification, and redistribution, is contained in * +! the files COPYING and Copyright.html. COPYING can be found at the root * +! of the source code distribution tree; Copyright.html can be found at the * +! root level of an installed copy of the electronic HDF5 document set and * +! is linked from the top-level documents page. It can also be found at * +! http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * +! access to either file, you may request a copy from help@hdfgroup.org. * +! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +! +! MAIN PROGRAM FOR PARALLEL HDF5 FORTRAN 2003 TESTS +! + +PROGRAM parallel_test_F03 + USE hdf5 + USE TH5_MISC + USE mpi + IMPLICIT NONE + + INTEGER :: mpierror ! MPI hdferror flag + INTEGER :: hdferror ! HDF hdferror flag + LOGICAL :: do_collective ! use collective MPI IO + LOGICAL :: do_chunk ! use chunking + INTEGER :: nerrors = 0 ! number of errors + INTEGER :: mpi_size ! number of processes in the group of communicator + INTEGER :: mpi_rank ! rank of the calling process in the communicator + ! + ! initialize MPI + ! + CALL mpi_init(mpierror) + IF (mpierror .NE. MPI_SUCCESS) WRITE(*,*) "MPI_INIT *FAILED*" + CALL mpi_comm_rank( MPI_COMM_WORLD, mpi_rank, mpierror ) + IF (mpierror .NE. MPI_SUCCESS) WRITE(*,*) "MPI_COMM_RANK *FAILED* Process = ", mpi_rank + CALL mpi_comm_size( MPI_COMM_WORLD, mpi_size, mpierror ) + IF (mpierror .NE. MPI_SUCCESS) WRITE(*,*) "MPI_COMM_SIZE *FAILED* Process = ", mpi_rank + + ! + ! initialize the HDF5 fortran interface + ! + CALL h5open_f(hdferror) + ! + ! test write/read several hyperslab datasets + ! + do_collective = .TRUE. + do_chunk = .FALSE. + IF (mpi_rank == 0) WRITE(*,*) 'Writing/Reading several hyperslab datasets (contiguous layout, collective MPI IO)' + CALL pmultiple_dset_hyper_rw(do_collective, do_chunk, mpi_size, mpi_rank, nerrors) + + do_collective = .FALSE. + do_chunk = .FALSE. + IF (mpi_rank == 0) WRITE(*,*) 'Writing/Reading several hyperslab datasets (contiguous layout, independent MPI IO)' + CALL pmultiple_dset_hyper_rw(do_collective, do_chunk, mpi_size, mpi_rank, nerrors) + + do_collective = .TRUE. + do_chunk = .TRUE. + IF (mpi_rank == 0) WRITE(*,*) 'Writing/Reading several hyperslab datasets (chunked, collective MPI IO)' + CALL pmultiple_dset_hyper_rw(do_collective, do_chunk, mpi_size, mpi_rank, nerrors) + + do_collective = .FALSE. + do_chunk = .TRUE. + IF (mpi_rank == 0) WRITE(*,*) 'Writing/Reading several hyperslab datasets (chunked, independent MPI IO)' + CALL pmultiple_dset_hyper_rw(do_collective, do_chunk, mpi_size, mpi_rank, nerrors) + + ! + ! close HDF5 interface + ! + CALL h5close_f(hdferror) + ! + ! close MPI + ! + IF (nerrors == 0) THEN + CALL mpi_finalize(mpierror) + IF (mpierror .NE. MPI_SUCCESS) THEN + WRITE(*,*) "MPI_FINALIZE *FAILED* Process = ", mpi_rank + ENDIF + ELSE + WRITE(*,*) 'Errors detected in process ', mpi_rank + CALL mpi_abort(MPI_COMM_WORLD, 1, mpierror) + IF (mpierror .NE. MPI_SUCCESS) THEN + WRITE(*,*) "MPI_ABORT *FAILED* Process = ", mpi_rank + ENDIF + ENDIF + +END PROGRAM parallel_test_F03 + diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index af6599a..e962a29 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -67,7 +67,7 @@ /****************/ /* Macros for iterating over chunks to operate on */ -#define H5D_CHUNK_GET_FIRST_NODE(map) (map->use_single ? (H5SL_node_t *)(1) : H5SL_first(map->sel_chunks)) +#define H5D_CHUNK_GET_FIRST_NODE(map) (map->use_single ? (H5SL_node_t *)(1) : H5SL_first(map->dset_sel_pieces)) #define H5D_CHUNK_GET_NODE_INFO(map, node) (map->use_single ? map->single_chunk_info : (H5D_chunk_info_t *)H5SL_item(node)) #define H5D_CHUNK_GET_NEXT_NODE(map, node) (map->use_single ? (H5SL_node_t *)NULL : H5SL_next(node)) @@ -216,14 +216,6 @@ typedef struct H5D_chunk_readvv_ud_t { hid_t dxpl_id; /* DXPL for operation */ } H5D_chunk_readvv_ud_t; -/* Callback info for file selection iteration */ -typedef struct H5D_chunk_file_iter_ud_t { - H5D_chunk_map_t *fm; /* File->memory chunk mapping info */ -#ifdef H5_HAVE_PARALLEL - const H5D_io_info_t *io_info; /* I/O info for operation */ -#endif /* H5_HAVE_PARALLEL */ -} H5D_chunk_file_iter_ud_t; - #ifdef H5_HAVE_PARALLEL /* information to construct a collective I/O operation for filling chunks */ typedef struct H5D_chunk_coll_info_t { @@ -238,19 +230,17 @@ typedef struct H5D_chunk_coll_info_t { /* Chunked layout operation callbacks */ static herr_t H5D__chunk_construct(H5F_t *f, H5D_t *dset); -static herr_t H5D__chunk_init(H5F_t *f, hid_t dxpl_id, const H5D_t *dset, - hid_t dapl_id); -static herr_t H5D__chunk_io_init(const H5D_io_info_t *io_info, +static herr_t H5D__chunk_init(H5F_t *f, hid_t dxpl_id, const H5D_t *dset, hid_t dapl_id); +static herr_t H5D__chunk_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, - const H5S_t *mem_space, H5D_chunk_map_t *fm); + const H5S_t *mem_space, H5D_dset_info_t *dinfo); static herr_t H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t *fm); + H5D_dset_info_t *dinfo); static herr_t H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t *fm); + H5D_dset_info_t *dinfo); static herr_t H5D__chunk_flush(H5D_t *dset, hid_t dxpl_id); -static herr_t H5D__chunk_io_term(const H5D_chunk_map_t *fm); static herr_t H5D__chunk_dest(H5D_t *dset, hid_t dxpl_id); /* "Nonexistent" layout operation callback */ @@ -274,16 +264,17 @@ static herr_t H5D__chunk_cinfo_cache_update(H5D_chunk_cached_t *last, const H5D_chunk_ud_t *udata); static hbool_t H5D__chunk_cinfo_cache_found(const H5D_chunk_cached_t *last, H5D_chunk_ud_t *udata); -static herr_t H5D__free_chunk_info(void *item, void *key, void *opdata); -static herr_t H5D__create_chunk_map_single(H5D_chunk_map_t *fm, - const H5D_io_info_t *io_info); -static herr_t H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, +static herr_t H5D__free_piece_info(void *item, void *key, void *opdata); +static herr_t H5D__create_piece_map_single(H5D_dset_info_t *di, + const H5D_io_info_t* io_info); +static herr_t H5D__create_piece_file_map_hyper(H5D_dset_info_t *di, const H5D_io_info_t *io_info); -static herr_t H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm); -static herr_t H5D__chunk_file_cb(void *elem, const H5T_t *type, unsigned ndims, - const hsize_t *coords, void *fm); -static herr_t H5D__chunk_mem_cb(void *elem, const H5T_t *type, unsigned ndims, - const hsize_t *coords, void *fm); +static herr_t H5D__create_piece_mem_map_hyper(const H5D_io_info_t *io_info, + const H5D_dset_info_t *dinfo); +static herr_t H5D__piece_file_cb(void H5_ATTR_UNUSED *elem, const H5T_t *type, unsigned ndims, + const hsize_t *coords, void *_opdata); +static herr_t H5D__piece_mem_cb(void *elem, const H5T_t *type, unsigned ndims, + const hsize_t *coords, void *_opdata); static unsigned H5D__chunk_hash_val(const H5D_shared_t *shared, const hsize_t *scaled); static herr_t H5D__chunk_flush_entry(const H5D_t *dset, hid_t dxpl_id, const H5D_dxpl_cache_t *dxpl_cache, H5D_rdcc_ent_t *ent, hbool_t reset); @@ -320,13 +311,13 @@ const H5D_layout_ops_t H5D_LOPS_CHUNK[1] = {{ H5D__chunk_read, H5D__chunk_write, #ifdef H5_HAVE_PARALLEL - H5D__chunk_collective_read, - H5D__chunk_collective_write, + H5D__collective_read, + H5D__collective_write, #endif /* H5_HAVE_PARALLEL */ NULL, NULL, H5D__chunk_flush, - H5D__chunk_io_term, + H5D__piece_io_term, H5D__chunk_dest }}; @@ -1082,25 +1073,23 @@ H5D__chunk_is_space_alloc(const H5O_storage_t *storage) FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__chunk_is_space_alloc() */ - /*------------------------------------------------------------------------- * Function: H5D__chunk_io_init * * Purpose: Performs initialization before any sort of I/O on the raw data + * This was derived from H5D__chunk_io_init for multi-dset work. * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Thursday, March 20, 2008 - * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, +H5D__chunk_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t *fm) + H5D_dset_info_t *dinfo) { - const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */ + const H5D_t *dataset = dinfo->dset; /* Local pointer to dataset info */ const H5T_t *mem_type = type_info->mem_type; /* Local pointer to memory datatype */ H5S_t *tmp_mspace = NULL; /* Temporary memory dataspace */ hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */ @@ -1112,22 +1101,24 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf H5SL_node_t *curr_node; /* Current node in skip list */ char bogus; /* "bogus" buffer to pass to selection iterator */ unsigned u; /* Local index variable */ + H5D_io_info_wrap_t io_info_wrap; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Get layout for dataset */ - fm->layout = &(dataset->shared->layout); - fm->nelmts = nelmts; + dinfo->layout = &(dataset->shared->layout); + /* num of element selected */ + dinfo->nelmts = nelmts; /* Check if the memory space is scalar & make equivalent memory space */ if((sm_ndims = H5S_GET_EXTENT_NDIMS(mem_space)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number") /* Set the number of dimensions for the memory dataspace */ - H5_CHECKED_ASSIGN(fm->m_ndims, unsigned, sm_ndims, int); + H5_CHECKED_ASSIGN(dinfo->m_ndims, unsigned, sm_ndims, int); /* Get rank for file dataspace */ - fm->f_ndims = f_ndims = dataset->shared->layout.u.chunk.ndims - 1; + dinfo->f_ndims = f_ndims = dataset->shared->layout.u.chunk.ndims - 1; /* Normalize hyperslab selections by adjusting them by the offset */ /* (It might be worthwhile to normalize both the file and memory dataspaces @@ -1139,31 +1130,17 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") /* Decide the number of chunks in each dimension*/ - for(u = 0; u < f_ndims; u++) { + for(u = 0; u < f_ndims; u++) /* Keep the size of the chunk dimensions as hsize_t for various routines */ - fm->chunk_dim[u] = fm->layout->u.chunk.dim[u]; - } /* end for */ - -#ifdef H5_HAVE_PARALLEL - /* Calculate total chunk in file map*/ - fm->select_chunk = NULL; - if(io_info->using_mpi_vfd) { - H5_CHECK_OVERFLOW(fm->layout->u.chunk.nchunks, hsize_t, size_t); - if(fm->layout->u.chunk.nchunks) { - if(NULL == (fm->select_chunk = (H5D_chunk_info_t **)H5MM_calloc((size_t)fm->layout->u.chunk.nchunks * sizeof(H5D_chunk_info_t *)))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") - } - } /* end if */ -#endif /* H5_HAVE_PARALLEL */ - + dinfo->chunk_dim[u] = dinfo->layout->u.chunk.dim[u]; /* Initialize "last chunk" information */ - fm->last_index = (hsize_t)-1; - fm->last_chunk_info = NULL; + dinfo->last_index = (hsize_t)-1; + dinfo->last_piece_info = NULL; /* Point at the dataspaces */ - fm->file_space = file_space; - fm->mem_space = mem_space; + dinfo->file_space = file_space; + dinfo->mem_space = mem_space; /* Special case for only one element in selection */ /* (usually appending a record) */ @@ -1173,8 +1150,8 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf #endif /* H5_HAVE_PARALLEL */ && H5S_SEL_ALL != H5S_GET_SELECT_TYPE(file_space)) { /* Initialize skip list for chunk selections */ - fm->sel_chunks = NULL; - fm->use_single = TRUE; + //io_info->sel_pieces = NULL; + dinfo->use_single = TRUE; /* Initialize single chunk dataspace */ if(NULL == dataset->shared->cache.chunk.single_space) { @@ -1183,29 +1160,29 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space") /* Resize chunk's dataspace dimensions to size of chunk */ - if(H5S_set_extent_real(dataset->shared->cache.chunk.single_space, fm->chunk_dim) < 0) + if(H5S_set_extent_real(dataset->shared->cache.chunk.single_space, dinfo->chunk_dim) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust chunk dimensions") /* Set the single chunk dataspace to 'all' selection */ if(H5S_select_all(dataset->shared->cache.chunk.single_space, TRUE) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "unable to set all selection") } /* end if */ - fm->single_space = dataset->shared->cache.chunk.single_space; - HDassert(fm->single_space); + dinfo->single_space = dataset->shared->cache.chunk.single_space; + HDassert(dinfo->single_space); - /* Allocate the single chunk information */ + /* Allocate the single piece information */ if(NULL == dataset->shared->cache.chunk.single_chunk_info) { if(NULL == (dataset->shared->cache.chunk.single_chunk_info = H5FL_MALLOC(H5D_chunk_info_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate piece info") } /* end if */ - fm->single_chunk_info = dataset->shared->cache.chunk.single_chunk_info; - HDassert(fm->single_chunk_info); + dinfo->single_chunk_info = dataset->shared->cache.chunk.single_chunk_info; + HDassert(dinfo->single_chunk_info); /* Reset chunk template information */ - fm->mchunk_tmpl = NULL; + dinfo->mchunk_tmpl = NULL; /* Set up chunk mapping for single element */ - if(H5D__create_chunk_map_single(fm, io_info) < 0) + if(H5D__create_piece_map_single(dinfo, io_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create chunk selections for single element") } /* end if */ else { @@ -1216,20 +1193,21 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf if(NULL == (dataset->shared->cache.chunk.sel_chunks = H5SL_create(H5SL_TYPE_HSIZE, NULL))) HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for chunk selections") } /* end if */ - fm->sel_chunks = dataset->shared->cache.chunk.sel_chunks; - HDassert(fm->sel_chunks); + dinfo->dset_sel_pieces = dataset->shared->cache.chunk.sel_chunks; + HDassert(dinfo->dset_sel_pieces); + HDassert(io_info->sel_pieces); /* We are not using single element mode */ - fm->use_single = FALSE; + dinfo->use_single = FALSE; /* Get type of selection on disk & in memory */ - if((fm->fsel_type = H5S_GET_SELECT_TYPE(file_space)) < H5S_SEL_NONE) + if((dinfo->fsel_type = H5S_GET_SELECT_TYPE(file_space)) < H5S_SEL_NONE) HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") - if((fm->msel_type = H5S_GET_SELECT_TYPE(mem_space)) < H5S_SEL_NONE) + if((dinfo->msel_type = H5S_GET_SELECT_TYPE(mem_space)) < H5S_SEL_NONE) HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") /* If the selection is NONE or POINTS, set the flag to FALSE */ - if(fm->fsel_type == H5S_SEL_POINTS || fm->fsel_type == H5S_SEL_NONE) + if(dinfo->fsel_type == H5S_SEL_POINTS || dinfo->fsel_type == H5S_SEL_NONE) sel_hyper_flag = FALSE; else sel_hyper_flag = TRUE; @@ -1237,61 +1215,60 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* Check if file selection is a not a hyperslab selection */ if(sel_hyper_flag) { /* Build the file selection for each chunk */ - if(H5D__create_chunk_file_map_hyper(fm, io_info) < 0) + if(H5D__create_piece_file_map_hyper(dinfo, io_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") /* Clean file chunks' hyperslab span "scratch" information */ - curr_node = H5SL_first(fm->sel_chunks); + curr_node = H5SL_first(dinfo->dset_sel_pieces); while(curr_node) { - H5D_chunk_info_t *chunk_info; /* Pointer chunk information */ + H5D_chunk_info_t *piece_info; /* Pointer piece information */ - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - HDassert(chunk_info); + /* Get pointer to piece's information */ + piece_info = (H5D_chunk_info_t *)H5SL_item(curr_node); + HDassert(piece_info); - /* Clean hyperslab span's "scratch" information */ - if(H5S_hyper_reset_scratch(chunk_info->fspace) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info") + /* only for current dset */ + if (piece_info->dset_info == dinfo) { + /* Clean hyperslab span's "scratch" information */ + if(H5S_hyper_reset_scratch(piece_info->fspace) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info") + } /* end if */ - /* Get the next chunk node in the skip list */ + /* Get the next piece node in the skip list */ curr_node = H5SL_next(curr_node); } /* end while */ } /* end if */ else { H5S_sel_iter_op_t iter_op; /* Operator for iteration */ - H5D_chunk_file_iter_ud_t udata; /* User data for iteration */ /* Create temporary datatypes for selection iteration */ if(NULL == (file_type = H5T_copy(dataset->shared->type, H5T_COPY_ALL))) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL, "unable to copy file datatype") - /* Initialize the user data */ - udata.fm = fm; -#ifdef H5_HAVE_PARALLEL - udata.io_info = io_info; -#endif /* H5_HAVE_PARALLEL */ - + /* set opdata for H5D__piece_mem_cb */ + io_info_wrap.io_info = io_info; + io_info_wrap.dinfo = dinfo; iter_op.op_type = H5S_SEL_ITER_OP_LIB; - iter_op.u.lib_op = H5D__chunk_file_cb; + iter_op.u.lib_op = H5D__piece_file_cb; /* Spaces might not be the same shape, iterate over the file selection directly */ - if(H5S_select_iterate(&bogus, file_type, file_space, &iter_op, &udata) < 0) + if(H5S_select_iterate(&bogus, file_type, file_space, &iter_op, &io_info_wrap) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") /* Reset "last chunk" info */ - fm->last_index = (hsize_t)-1; - fm->last_chunk_info = NULL; + dinfo->last_index = (hsize_t)-1; + dinfo->last_piece_info = NULL; } /* end else */ /* Build the memory selection for each chunk */ if(sel_hyper_flag && H5S_select_shape_same(file_space, mem_space) == TRUE) { /* Reset chunk template information */ - fm->mchunk_tmpl = NULL; + dinfo->mchunk_tmpl = NULL; - /* If the selections are the same shape, use the file chunk information - * to generate the memory chunk information quickly. + /* If the selections are the same shape, use the file chunk + * information to generate the memory chunk information quickly. */ - if(H5D__create_chunk_mem_map_hyper(fm) < 0) + if(H5D__create_piece_mem_map_hyper(io_info, dinfo) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections") } /* end if */ else { @@ -1307,7 +1284,7 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select memory space") /* Save chunk template information */ - fm->mchunk_tmpl = tmp_mspace; + dinfo->mchunk_tmpl = tmp_mspace; /* Create temporary datatypes for selection iteration */ if(!file_type) { @@ -1318,33 +1295,37 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* Create selection iterator for memory selection */ if(0 == (elmt_size = H5T_get_size(mem_type))) HGOTO_ERROR(H5E_DATATYPE, H5E_BADSIZE, FAIL, "datatype size invalid") - if(H5S_select_iter_init(&(fm->mem_iter), mem_space, elmt_size) < 0) + if(H5S_select_iter_init(&(dinfo->mem_iter), mem_space, elmt_size) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") iter_init = TRUE; /* Selection iteration info has been initialized */ + /* set opdata for H5D__piece_mem_cb */ + io_info_wrap.io_info = io_info; + io_info_wrap.dinfo = dinfo; iter_op.op_type = H5S_SEL_ITER_OP_LIB; - iter_op.u.lib_op = H5D__chunk_mem_cb; + iter_op.u.lib_op = H5D__piece_mem_cb; /* Spaces aren't the same shape, iterate over the memory selection directly */ - if(H5S_select_iterate(&bogus, file_type, file_space, &iter_op, fm) < 0) + if(H5S_select_iterate(&bogus, file_type, file_space, &iter_op, &io_info_wrap) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections") /* Clean up hyperslab stuff, if necessary */ - if(fm->msel_type != H5S_SEL_POINTS) { - /* Clean memory chunks' hyperslab span "scratch" information */ - curr_node = H5SL_first(fm->sel_chunks); + if(dinfo->msel_type != H5S_SEL_POINTS) { + /* Clean memory pieces' hyperslab span "scratch" information */ + curr_node = H5SL_first(dinfo->dset_sel_pieces); + while(curr_node) { - H5D_chunk_info_t *chunk_info; /* Pointer chunk information */ + H5D_chunk_info_t *piece_info; /* Pointer piece information */ - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - HDassert(chunk_info); + /* Get pointer to piece's information */ + piece_info = (H5D_chunk_info_t *)H5SL_item(curr_node); + HDassert(piece_info); /* Clean hyperslab span's "scratch" information */ - if(H5S_hyper_reset_scratch(chunk_info->mspace) < 0) + if(H5S_hyper_reset_scratch(piece_info->mspace) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info") - /* Get the next chunk node in the skip list */ + /* Get the next piece node in the skip list */ curr_node = H5SL_next(curr_node); } /* end while */ } /* end if */ @@ -1354,28 +1335,23 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf done: /* Release the [potentially partially built] chunk mapping information if an error occurs */ if(ret_value < 0) { - if(tmp_mspace && !fm->mchunk_tmpl) { + if(tmp_mspace && !dinfo->mchunk_tmpl) if(H5S_close(tmp_mspace) < 0) HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory chunk dataspace template") - } /* end if */ - if(H5D__chunk_io_term(fm) < 0) + if(H5D__piece_io_term(io_info, dinfo) < 0) HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release chunk mapping") } /* end if */ - /* Reset the global dataspace info */ - fm->file_space = NULL; - fm->mem_space = NULL; - - if(iter_init && H5S_SELECT_ITER_RELEASE(&(fm->mem_iter)) < 0) + if(iter_init && H5S_SELECT_ITER_RELEASE(&(dinfo->mem_iter)) < 0) HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") if(file_type && (H5T_close(file_type) < 0)) HDONE_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "Can't free temporary datatype") - if(file_space_normalized) { + + if(file_space_normalized) /* (Casting away const OK -QAK) */ if(H5S_hyper_denormalize_offset((H5S_t *)file_space, old_offset) < 0) HDONE_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") - } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__chunk_io_init() */ @@ -1476,149 +1452,148 @@ H5D__chunk_mem_realloc(void *chk, size_t size, const H5O_pline_t *pline) } /* H5D__chunk_mem_realloc() */ -/*-------------------------------------------------------------------------- - NAME - H5D__free_chunk_info - PURPOSE - Internal routine to destroy a chunk info node - USAGE - void H5D__free_chunk_info(chunk_info) - void *chunk_info; IN: Pointer to chunk info to destroy - RETURNS - No return value - DESCRIPTION - Releases all the memory for a chunk info node. Called by H5SL_free - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------- + * Function: H5D__free_piece_info + * + * Purpose: Performs initialization before any sort of I/O on the raw data + * This was derived from H5D__free_chunk_info for multi-dset work. + * + * PURPOSE + * Releases all the memory for a piece info node. + * + * Parameter + * H5D_chunk_info_t *item; IN: Pointer to piece info to destroy + * + * RETURNS + * No return value + * + * Programmer: Jonathan Kim Nov, 2013 + *------------------------------------------------------------------------- + */ static herr_t -H5D__free_chunk_info(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *opdata) +H5D__free_piece_info(void *item, void H5_ATTR_UNUSED *key, void H5_ATTR_UNUSED *opdata) { - H5D_chunk_info_t *chunk_info = (H5D_chunk_info_t *)item; + H5D_chunk_info_t *piece_info = (H5D_chunk_info_t *)item; FUNC_ENTER_STATIC_NOERR - HDassert(chunk_info); + HDassert(piece_info); - /* Close the chunk's file dataspace, if it's not shared */ - if(!chunk_info->fspace_shared) - (void)H5S_close(chunk_info->fspace); + /* Close the piece's file dataspace, if it's not shared */ + if(!piece_info->fspace_shared) + (void)H5S_close(piece_info->fspace); else - H5S_select_all(chunk_info->fspace, TRUE); + H5S_select_all(piece_info->fspace, TRUE); - /* Close the chunk's memory dataspace, if it's not shared */ - if(!chunk_info->mspace_shared && chunk_info->mspace) - (void)H5S_close(chunk_info->mspace); + /* Close the piece's memory dataspace, if it's not shared */ + if(!piece_info->mspace_shared && piece_info->mspace) + (void)H5S_close(piece_info->mspace); - /* Free the actual chunk info */ - chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info); + /* Free the actual piece info */ + piece_info = H5FL_FREE(H5D_chunk_info_t, piece_info); FUNC_LEAVE_NOAPI(0) -} /* H5D__free_chunk_info() */ +} /* H5D__free_piece_info() */ - /*------------------------------------------------------------------------- - * Function: H5D__create_chunk_map_single + * Function: H5D__create_piece_map_single * - * Purpose: Create chunk selections when appending a single record + * Purpose: Create piece selections when appending a single record + * This was derived from H5D__create_chunk_map_single for + * multi-dset work. * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Tuesday, November 20, 2007 - * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ static herr_t -H5D__create_chunk_map_single(H5D_chunk_map_t *fm, const H5D_io_info_t -#ifndef H5_HAVE_PARALLEL - H5_ATTR_UNUSED -#endif /* H5_HAVE_PARALLEL */ - *io_info) +H5D__create_piece_map_single(H5D_dset_info_t *di, + const H5D_io_info_t *io_info) { - H5D_chunk_info_t *chunk_info; /* Chunk information to insert into skip list */ + H5D_chunk_info_t *piece_info; /* Piece information to insert into skip list */ hsize_t coords[H5O_LAYOUT_NDIMS]; /* Coordinates of chunk */ hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ unsigned u; /* Local index variable */ + H5D_chunk_ud_t udata; /* User data for querying piece info */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC + FUNC_ENTER_STATIC_TAG(io_info->md_dxpl_id, di->dset->oloc.addr, FAIL) /* Sanity check */ - HDassert(fm->f_ndims > 0); + HDassert(di->f_ndims > 0); /* Get coordinate for selection */ - if(H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0) + if(H5S_SELECT_BOUNDS(di->file_space, sel_start, sel_end) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") - /* Initialize the 'single chunk' file & memory chunk information */ - chunk_info = fm->single_chunk_info; - chunk_info->chunk_points = 1; + /* Initialize the 'single piece' file & memory piece information */ + piece_info = di->single_chunk_info; + piece_info->piece_points = 1; /* Set chunk location & hyperslab size */ - for(u = 0; u < fm->f_ndims; u++) { + for(u = 0; u < di->f_ndims; u++) { HDassert(sel_start[u] == sel_end[u]); - chunk_info->scaled[u] = sel_start[u] / fm->layout->u.chunk.dim[u]; - coords[u] = chunk_info->scaled[u] * fm->layout->u.chunk.dim[u]; + piece_info->scaled[u] = sel_start[u] / di->layout->u.chunk.dim[u]; + coords[u] = piece_info->scaled[u] * di->layout->u.chunk.dim[u]; } /* end for */ - chunk_info->scaled[fm->f_ndims] = 0; + piece_info->scaled[di->f_ndims] = 0; /* Calculate the index of this chunk */ - chunk_info->index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, chunk_info->scaled); + piece_info->index = H5VM_array_offset_pre(di->f_ndims, di->layout->u.chunk.down_chunks, piece_info->scaled); /* Copy selection for file's dataspace into chunk dataspace */ - if(H5S_select_copy(fm->single_space, fm->file_space, FALSE) < 0) + if(H5S_select_copy(di->single_space, di->file_space, FALSE) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file selection") /* Move selection back to have correct offset in chunk */ - if(H5S_SELECT_ADJUST_U(fm->single_space, coords) < 0) + if(H5S_SELECT_ADJUST_U(di->single_space, coords) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection") -#ifdef H5_HAVE_PARALLEL - /* store chunk selection information */ - if(io_info->using_mpi_vfd) - fm->select_chunk[chunk_info->index] = chunk_info; -#endif /* H5_HAVE_PARALLEL */ - /* Set the file dataspace for the chunk to the shared 'single' dataspace */ - chunk_info->fspace = fm->single_space; + piece_info->fspace = di->single_space; /* Indicate that the chunk's file dataspace is shared */ - chunk_info->fspace_shared = TRUE; + piece_info->fspace_shared = TRUE; /* Just point at the memory dataspace & selection */ /* (Casting away const OK -QAK) */ - chunk_info->mspace = (H5S_t *)fm->mem_space; + piece_info->mspace = (H5S_t *)di->mem_space; /* Indicate that the chunk's memory dataspace is shared */ - chunk_info->mspace_shared = TRUE; + piece_info->mspace_shared = TRUE; + + /* make connection to related dset info from this piece_info */ + piece_info->dset_info = di; + + /* get piece file address */ + if(H5D__chunk_lookup(piece_info->dset_info->dset, io_info->md_dxpl_id, piece_info->scaled, &udata) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") + piece_info->faddr = udata.chunk_block.offset; + + /* Insert piece into global piece skiplist */ + if(H5SL_insert(io_info->sel_pieces, piece_info, &piece_info->faddr) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into skip list") done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__create_chunk_map_single() */ + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5D__create_piece_map_single() */ - /*------------------------------------------------------------------------- - * Function: H5D__create_chunk_file_map_hyper + * Function: H5D__create_piece_file_map_hyper * * Purpose: Create all chunk selections in file. + * This was derived from H5D__create_chunk_file_map_hyper for + * multi-dset work. * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Thursday, May 29, 2003 - * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ static herr_t -H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t -#ifndef H5_HAVE_PARALLEL - H5_ATTR_UNUSED -#endif /* H5_HAVE_PARALLEL */ - *io_info) +H5D__create_piece_file_map_hyper(H5D_dset_info_t *dinfo, const H5D_io_info_t *io_info) { hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ @@ -1633,39 +1608,41 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC + FUNC_ENTER_STATIC_TAG(io_info->md_dxpl_id, dinfo->dset->oloc.addr, FAIL) /* Sanity check */ - HDassert(fm->f_ndims>0); + HDassert(dinfo->f_ndims > 0); /* Get number of elements selected in file */ - sel_points = fm->nelmts; + sel_points = dinfo->nelmts; /* Get bounding box for selection (to reduce the number of chunks to iterate over) */ - if(H5S_SELECT_BOUNDS(fm->file_space, sel_start, sel_end) < 0) + if(H5S_SELECT_BOUNDS(dinfo->file_space, sel_start, sel_end) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") /* Set initial chunk location & hyperslab size */ - for(u = 0; u < fm->f_ndims; u++) { - scaled[u] = start_scaled[u] = sel_start[u] / fm->layout->u.chunk.dim[u]; - coords[u] = start_coords[u] = scaled[u] * fm->layout->u.chunk.dim[u]; - end[u] = (coords[u] + fm->chunk_dim[u]) - 1; + for(u = 0; u < dinfo->f_ndims; u++) { + scaled[u] = start_scaled[u] = sel_start[u] / dinfo->layout->u.chunk.dim[u]; + coords[u] = start_coords[u] = scaled[u] * dinfo->layout->u.chunk.dim[u]; + end[u] = (coords[u] + dinfo->chunk_dim[u]) - 1; } /* end for */ /* Calculate the index of this chunk */ - chunk_index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, scaled); + chunk_index = H5VM_array_offset_pre(dinfo->f_ndims, dinfo->layout->u.chunk.down_chunks, scaled); /* Iterate through each chunk in the dataset */ while(sel_points) { + H5D_chunk_ud_t udata; /* User data for querying chunk info */ + /* Check for intersection of temporary chunk and file selection */ /* (Casting away const OK - QAK) */ - if(TRUE == H5S_hyper_intersect_block((H5S_t *)fm->file_space, coords, end)) { + if(TRUE == H5S_hyper_intersect_block((H5S_t *)dinfo->file_space, coords, end)) { H5S_t *tmp_fchunk; /* Temporary file dataspace */ - H5D_chunk_info_t *new_chunk_info; /* chunk information to insert into skip list */ + H5D_chunk_info_t *new_piece_info; /* chunk information to insert into skip list */ hssize_t schunk_points; /* Number of elements in chunk selection */ /* Create "temporary" chunk for selection operations (copy file space) */ - if(NULL == (tmp_fchunk = H5S_copy(fm->file_space, TRUE, FALSE))) + if(NULL == (tmp_fchunk = H5S_copy(dinfo->file_space, TRUE, FALSE))) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") /* Make certain selections are stored in span tree form (not "optimized hyperslab" or "all") */ @@ -1675,13 +1652,13 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t } /* end if */ /* "AND" temporary chunk and current chunk */ - if(H5S_select_hyperslab(tmp_fchunk,H5S_SELECT_AND,coords,NULL,fm->chunk_dim,NULL) < 0) { + if(H5S_select_hyperslab(tmp_fchunk,H5S_SELECT_AND,coords,NULL,dinfo->chunk_dim,NULL) < 0) { (void)H5S_close(tmp_fchunk); HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't create chunk selection") } /* end if */ /* Resize chunk's dataspace dimensions to size of chunk */ - if(H5S_set_extent_real(tmp_fchunk,fm->chunk_dim) < 0) { + if(H5S_set_extent_real(tmp_fchunk,dinfo->chunk_dim) < 0) { (void)H5S_close(tmp_fchunk); HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk dimensions") } /* end if */ @@ -1695,7 +1672,7 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t /* Add temporary chunk to the list of chunks */ /* Allocate the file & memory chunk information */ - if (NULL==(new_chunk_info = H5FL_MALLOC(H5D_chunk_info_t))) { + if (NULL == (new_piece_info = H5FL_MALLOC(H5D_chunk_info_t))) { (void)H5S_close(tmp_fchunk); HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") } /* end if */ @@ -1703,39 +1680,55 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t /* Initialize the chunk information */ /* Set the chunk index */ - new_chunk_info->index=chunk_index; + new_piece_info->index=chunk_index; -#ifdef H5_HAVE_PARALLEL - /* Store chunk selection information, for multi-chunk I/O */ - if(io_info->using_mpi_vfd) - fm->select_chunk[chunk_index] = new_chunk_info; -#endif /* H5_HAVE_PARALLEL */ +/*MSB #ifdef H5_HAVE_PARALLEL */ +/* /\* Store chunk selection information, for multi-chunk I/O *\/ */ +/* if(io_info->using_mpi_vfd) */ +/* dinfo->select_chunk[chunk_index] = new_piece_info; */ +/* #endif /\* H5_HAVE_PARALLEL *\/ */ /* Set the file chunk dataspace */ - new_chunk_info->fspace = tmp_fchunk; - new_chunk_info->fspace_shared = FALSE; + new_piece_info->fspace = tmp_fchunk; + new_piece_info->fspace_shared = FALSE; /* Set the memory chunk dataspace */ - new_chunk_info->mspace=NULL; - new_chunk_info->mspace_shared = FALSE; + new_piece_info->mspace=NULL; + new_piece_info->mspace_shared = FALSE; /* Copy the chunk's scaled coordinates */ - HDmemcpy(new_chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); - new_chunk_info->scaled[fm->f_ndims] = 0; + HDmemcpy(new_piece_info->scaled, scaled, sizeof(hsize_t) * dinfo->f_ndims); + new_piece_info->scaled[dinfo->f_ndims] = 0; - /* Copy the chunk's scaled coordinates */ - HDmemcpy(new_chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); + /* make connection to related dset info from this piece_info */ + new_piece_info->dset_info = dinfo; + + /* get chunk file address */ + if(H5D__chunk_lookup(new_piece_info->dset_info->dset, io_info->md_dxpl_id, new_piece_info->scaled, &udata) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") - /* Insert the new chunk into the skip list */ - if(H5SL_insert(fm->sel_chunks, new_chunk_info, &new_chunk_info->index) < 0) { - H5D__free_chunk_info(new_chunk_info, NULL, NULL); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into skip list") +#ifdef H5_HAVE_PARALLEL /*MSB don't do check this if swmr is being used*/ + if(io_info->using_mpi_vfd) { + new_piece_info->faddr = udata.chunk_block.offset; + if(HADDR_UNDEF != udata.chunk_block.offset) { + /* Insert the new piece into the global skip list */ + if(H5SL_insert(io_info->sel_pieces, new_piece_info, &new_piece_info->faddr) < 0) { + H5D__free_piece_info(new_piece_info, NULL, NULL); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into skip list") + } /* end if */ + } + } +#endif + /* Insert the new piece into the dataset skip list */ + if(H5SL_insert(dinfo->dset_sel_pieces, new_piece_info, &new_piece_info->index) < 0) { + H5D__free_piece_info(new_piece_info, NULL, NULL); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into dataset skip list") } /* end if */ /* Get number of elements selected in chunk */ if((schunk_points = H5S_GET_SELECT_NPOINTS(tmp_fchunk)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection # of elements") - H5_CHECKED_ASSIGN(new_chunk_info->chunk_points, uint32_t, schunk_points, hssize_t); + H5_CHECKED_ASSIGN(new_piece_info->piece_points, uint32_t, schunk_points, hssize_t); /* Decrement # of points left in file selection */ sel_points -= (hsize_t)schunk_points; @@ -1749,12 +1742,12 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t chunk_index++; /* Set current increment dimension */ - curr_dim=(int)fm->f_ndims-1; + curr_dim=(int)dinfo->f_ndims-1; /* Increment chunk location in fastest changing dimension */ - H5_CHECK_OVERFLOW(fm->chunk_dim[curr_dim],hsize_t,hssize_t); - coords[curr_dim]+=fm->chunk_dim[curr_dim]; - end[curr_dim]+=fm->chunk_dim[curr_dim]; + H5_CHECK_OVERFLOW(dinfo->chunk_dim[curr_dim],hsize_t,hssize_t); + coords[curr_dim]+=dinfo->chunk_dim[curr_dim]; + end[curr_dim]+=dinfo->chunk_dim[curr_dim]; scaled[curr_dim]++; /* Bring chunk location back into bounds, if necessary */ @@ -1763,164 +1756,164 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t /* Reset current dimension's location to 0 */ scaled[curr_dim] = start_scaled[curr_dim]; coords[curr_dim] = start_coords[curr_dim]; /*lint !e771 The start_coords will always be initialized */ - end[curr_dim] = (coords[curr_dim] + fm->chunk_dim[curr_dim]) - 1; + end[curr_dim] = (coords[curr_dim] + dinfo->chunk_dim[curr_dim]) - 1; /* Decrement current dimension */ curr_dim--; /* Increment chunk location in current dimension */ scaled[curr_dim]++; - coords[curr_dim] += fm->chunk_dim[curr_dim]; - end[curr_dim] = (coords[curr_dim] + fm->chunk_dim[curr_dim]) - 1; + coords[curr_dim] += dinfo->chunk_dim[curr_dim]; + end[curr_dim] = (coords[curr_dim] + dinfo->chunk_dim[curr_dim]) - 1; } while(coords[curr_dim] > sel_end[curr_dim]); /* Re-calculate the index of this chunk */ - chunk_index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, scaled); + chunk_index = H5VM_array_offset_pre(dinfo->f_ndims, dinfo->layout->u.chunk.down_chunks, scaled); } /* end if */ } /* end while */ done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__create_chunk_file_map_hyper() */ + FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) +} /* end H5D__create_piece_file_map_hyper() */ - /*------------------------------------------------------------------------- - * Function: H5D__create_chunk_mem_map_hyper + * Function: H5D__create_piece_mem_map_hyper * * Purpose: Create all chunk selections in memory by copying the file - * chunk selections and adjusting their offsets to be correct - * for the memory. + * chunk selections and adjusting their offsets to be correct + * for the memory. + * This was derived from H5D__create_chunk_mem_map_hyper for + * multi-dset work. * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Thursday, May 29, 2003 + * Programmer: Jonathan Kim Nov, 2013 * * Assumptions: That the file and memory selections are the same shape. - * *------------------------------------------------------------------------- */ static herr_t -H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm) +H5D__create_piece_mem_map_hyper(const H5D_io_info_t H5_ATTR_UNUSED *io_info, const H5D_dset_info_t *dinfo) { H5SL_node_t *curr_node; /* Current node in skip list */ hsize_t file_sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ hsize_t file_sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ hsize_t mem_sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ hsize_t mem_sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ - hssize_t adjust[H5O_LAYOUT_NDIMS]; /* Adjustment to make to all file chunks */ - hssize_t chunk_adjust[H5O_LAYOUT_NDIMS]; /* Adjustment to make to a particular chunk */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ + hssize_t adjust[H5O_LAYOUT_NDIMS]; /* Adjustment to make to all file chunks */ + hssize_t piece_adjust[H5O_LAYOUT_NDIMS]; /* Adjustment to make to a particular chunk */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Sanity check */ - HDassert(fm->f_ndims>0); + HDassert(dinfo->f_ndims>0); /* Check for all I/O going to a single chunk */ - if(H5SL_count(fm->sel_chunks)==1) { - H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ + //if(H5SL_count(io_info->sel_pieces) == 1) { + if(H5SL_count(dinfo->dset_sel_pieces) == 1) { + H5D_chunk_info_t *piece_info; /* Pointer to piece information */ /* Get the node */ - curr_node=H5SL_first(fm->sel_chunks); + //curr_node=H5SL_first(io_info->sel_pieces); + curr_node=H5SL_first(dinfo->dset_sel_pieces); - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - HDassert(chunk_info); + /* Get pointer to piece's information */ + piece_info = (H5D_chunk_info_t *)H5SL_item(curr_node); + HDassert(piece_info); /* Just point at the memory dataspace & selection */ /* (Casting away const OK -QAK) */ - chunk_info->mspace = (H5S_t *)fm->mem_space; + piece_info->mspace = (H5S_t *)dinfo->mem_space; - /* Indicate that the chunk's memory space is shared */ - chunk_info->mspace_shared = TRUE; + /* Indicate that the piece's memory space is shared */ + piece_info->mspace_shared = TRUE; } /* end if */ else { /* Get bounding box for file selection */ - if(H5S_SELECT_BOUNDS(fm->file_space, file_sel_start, file_sel_end) < 0) + if(H5S_SELECT_BOUNDS(dinfo->file_space, file_sel_start, file_sel_end) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") /* Get bounding box for memory selection */ - if(H5S_SELECT_BOUNDS(fm->mem_space, mem_sel_start, mem_sel_end) < 0) + if(H5S_SELECT_BOUNDS(dinfo->mem_space, mem_sel_start, mem_sel_end) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") /* Calculate the adjustment for memory selection from file selection */ - HDassert(fm->m_ndims==fm->f_ndims); - for(u=0; u<fm->f_ndims; u++) { + HDassert(dinfo->m_ndims==dinfo->f_ndims); + for(u=0; u<dinfo->f_ndims; u++) { H5_CHECK_OVERFLOW(file_sel_start[u],hsize_t,hssize_t); H5_CHECK_OVERFLOW(mem_sel_start[u],hsize_t,hssize_t); adjust[u]=(hssize_t)file_sel_start[u]-(hssize_t)mem_sel_start[u]; } /* end for */ - /* Iterate over each chunk in the chunk list */ - curr_node=H5SL_first(fm->sel_chunks); - while(curr_node) { - H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ + /* Iterate over each piece in the dataset's piece skiplist */ + HDassert(dinfo->dset_sel_pieces); + curr_node=H5SL_first(dinfo->dset_sel_pieces); - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - HDassert(chunk_info); + while(curr_node) { + H5D_chunk_info_t *piece_info; /* Pointer to piece information */ - /* Copy the information */ + /* Get pointer to piece's information */ + piece_info = (H5D_chunk_info_t *)H5SL_item(curr_node); + HDassert(piece_info); /* Copy the memory dataspace */ - if((chunk_info->mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL) + if((piece_info->mspace = H5S_copy(dinfo->mem_space, TRUE, FALSE)) == NULL) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") /* Release the current selection */ - if(H5S_SELECT_RELEASE(chunk_info->mspace) < 0) + if(H5S_SELECT_RELEASE(piece_info->mspace) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection") - /* Copy the file chunk's selection */ - if(H5S_select_copy(chunk_info->mspace,chunk_info->fspace,FALSE) < 0) + /* Copy the file piece's selection */ + if(H5S_select_copy(piece_info->mspace, piece_info->fspace, FALSE) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy selection") /* Compute the adjustment for this chunk */ - for(u = 0; u < fm->f_ndims; u++) { + for(u = 0; u < dinfo->f_ndims; u++) { hsize_t coords[H5O_LAYOUT_NDIMS]; /* Current coordinates of chunk */ /* Compute the chunk coordinates from the scaled coordinates */ - coords[u] = chunk_info->scaled[u] * fm->layout->u.chunk.dim[u]; + coords[u] = piece_info->scaled[u] * dinfo->layout->u.chunk.dim[u]; /* Compensate for the chunk offset */ H5_CHECK_OVERFLOW(coords[u], hsize_t, hssize_t); - chunk_adjust[u] = adjust[u] - (hssize_t)coords[u]; /*lint !e771 The adjust array will always be initialized */ + piece_adjust[u] = adjust[u] - (hssize_t)coords[u]; /*lint !e771 The adjust array will always be initialized */ } /* end for */ /* Adjust the selection */ - if(H5S_hyper_adjust_s(chunk_info->mspace,chunk_adjust) < 0) /*lint !e772 The chunk_adjust array will always be initialized */ + if(H5S_hyper_adjust_s(piece_info->mspace,piece_adjust) < 0) /*lint !e772 The piece_adjust array will always be initialized */ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk selection") - /* Get the next chunk node in the skip list */ + /* Get the next piece node in the skip list */ curr_node=H5SL_next(curr_node); } /* end while */ } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__create_chunk_mem_map_hyper() */ +} /* end H5D__create_piece_mem_map_hyper() */ - /*------------------------------------------------------------------------- - * Function: H5D__chunk_file_cb + * Function: H5D__piece_file_cb * * Purpose: Callback routine for file selection iterator. Used when * creating selections in file for each point selected. * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Wednesday, July 23, 2003 - * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_file_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims, const hsize_t *coords, void *_udata) +H5D__piece_file_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims, const hsize_t *coords, void *_opdata) { - H5D_chunk_file_iter_ud_t *udata = (H5D_chunk_file_iter_ud_t *)_udata; /* User data for operation */ - H5D_chunk_map_t *fm = udata->fm; /* File<->memory chunk mapping info */ - H5D_chunk_info_t *chunk_info; /* Chunk information for current chunk */ + H5D_io_info_wrap_t *opdata = (H5D_io_info_wrap_t *)_opdata; + H5D_io_info_t *io_info = (H5D_io_info_t *) opdata->io_info; /* io info for mumti dset */ + H5D_dset_info_t *dinfo = (H5D_dset_info_t *) opdata->dinfo; /* File<->memory piece mapping info */ + H5D_chunk_info_t *piece_info; /* Chunk information for current piece */ + hsize_t coords_in_chunk[H5O_LAYOUT_NDIMS]; /* Coordinates of element in chunk */ hsize_t chunk_index; /* Chunk index */ hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */ @@ -1930,113 +1923,130 @@ H5D__chunk_file_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, FUNC_ENTER_STATIC /* Calculate the index of this chunk */ - chunk_index = H5VM_chunk_index_scaled(ndims, coords, fm->layout->u.chunk.dim, fm->layout->u.chunk.down_chunks, scaled); + chunk_index = H5VM_chunk_index_scaled(ndims, coords, dinfo->layout->u.chunk.dim, + dinfo->layout->u.chunk.down_chunks, scaled); /* Find correct chunk in file & memory skip list */ - if(chunk_index==fm->last_index) { + if(chunk_index == dinfo->last_index) { /* If the chunk index is the same as the last chunk index we used, * get the cached info to operate on. */ - chunk_info = fm->last_chunk_info; + piece_info = dinfo->last_piece_info; } /* end if */ else { + haddr_t prev_tag = HADDR_UNDEF; + H5D_chunk_ud_t udata; /* User data for querying piece info */ + /* If the chunk index is not the same as the last chunk index we used, - * find the chunk in the skip list. - */ - /* Get the chunk node from the skip list */ - if(NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_search(fm->sel_chunks, &chunk_index))) { + * search for the chunk in the skip list. If we do not find it, create + * a new node. */ + if(NULL == (piece_info = (H5D_chunk_info_t *)H5SL_search(dinfo->dset_sel_pieces, &chunk_index))) { H5S_t *fspace; /* Memory chunk's dataspace */ /* Allocate the file & memory chunk information */ - if (NULL==(chunk_info = H5FL_MALLOC (H5D_chunk_info_t))) + if (NULL==(piece_info = H5FL_MALLOC (H5D_chunk_info_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") /* Initialize the chunk information */ /* Set the chunk index */ - chunk_info->index=chunk_index; + piece_info->index = chunk_index; /* Create a dataspace for the chunk */ - if((fspace = H5S_create_simple(fm->f_ndims,fm->chunk_dim,NULL))==NULL) { - chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info); + if((fspace = H5S_create_simple(dinfo->f_ndims, dinfo->chunk_dim, NULL)) == NULL) { + piece_info = H5FL_FREE(H5D_chunk_info_t, piece_info); HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "unable to create dataspace for chunk") } /* end if */ /* De-select the chunk space */ if(H5S_select_none(fspace) < 0) { (void)H5S_close(fspace); - chunk_info = H5FL_FREE(H5D_chunk_info_t, chunk_info); + piece_info = H5FL_FREE(H5D_chunk_info_t, piece_info); HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to de-select dataspace") } /* end if */ /* Set the file chunk dataspace */ - chunk_info->fspace = fspace; - chunk_info->fspace_shared = FALSE; + piece_info->fspace = fspace; + piece_info->fspace_shared = FALSE; /* Set the memory chunk dataspace */ - chunk_info->mspace = NULL; - chunk_info->mspace_shared = FALSE; + piece_info->mspace = NULL; + piece_info->mspace_shared = FALSE; /* Set the number of selected elements in chunk to zero */ - chunk_info->chunk_points = 0; + piece_info->piece_points = 0; /* Set the chunk's scaled coordinates */ - HDmemcpy(chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); - chunk_info->scaled[fm->f_ndims] = 0; - HDmemcpy(chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); - - /* Insert the new chunk into the skip list */ - if(H5SL_insert(fm->sel_chunks,chunk_info,&chunk_info->index) < 0) { - H5D__free_chunk_info(chunk_info,NULL,NULL); - HGOTO_ERROR(H5E_DATASPACE,H5E_CANTINSERT,FAIL,"can't insert chunk into skip list") + HDmemcpy(piece_info->scaled, scaled, sizeof(hsize_t) * dinfo->f_ndims); + piece_info->scaled[dinfo->f_ndims] = 0; + + /* make connection to related dset info from this piece_info */ + piece_info->dset_info = dinfo; + + /* Insert the new piece into the dataset skip list */ + if(H5SL_insert(dinfo->dset_sel_pieces, piece_info, &piece_info->index) < 0) { + H5D__free_piece_info(piece_info, NULL, NULL); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into dataset skip list") } /* end if */ - } /* end if */ -#ifdef H5_HAVE_PARALLEL - /* Store chunk selection information, for collective multi-chunk I/O */ - if(udata->io_info->using_mpi_vfd) - fm->select_chunk[chunk_index] = chunk_info; -#endif /* H5_HAVE_PARALLEL */ + /* set metadata tagging with dset oheader addr for H5D__chunk_lookup */ + if(H5AC_tag(io_info->md_dxpl_id, piece_info->dset_info->dset->oloc.addr, &prev_tag) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + /* get chunk file address */ + if(H5D__chunk_lookup(piece_info->dset_info->dset, io_info->md_dxpl_id, piece_info->scaled, &udata) < 0) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "couldn't get chunk info from skip list") + piece_info->faddr = udata.chunk_block.offset; + /* Reset metadata tagging */ + if(H5AC_tag(io_info->md_dxpl_id, prev_tag, NULL) < 0) + HDONE_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + + if(HADDR_UNDEF != udata.chunk_block.offset) { + /* Insert the new piece into the global skip list */ + if(H5SL_insert(io_info->sel_pieces, piece_info, &piece_info->faddr) < 0) { + H5D__free_piece_info(piece_info,NULL,NULL); + HGOTO_ERROR(H5E_DATASPACE,H5E_CANTINSERT,FAIL,"can't insert chunk into skip list") + } /* end if */ + } + } /* end if */ /* Update the "last chunk seen" information */ - fm->last_index = chunk_index; - fm->last_chunk_info = chunk_info; + dinfo->last_index = chunk_index; + dinfo->last_piece_info = piece_info; } /* end else */ /* Get the offset of the element within the chunk */ - for(u = 0; u < fm->f_ndims; u++) - coords_in_chunk[u] = coords[u] - (scaled[u] * fm->layout->u.chunk.dim[u]); + for(u = 0; u < dinfo->f_ndims; u++) + coords_in_chunk[u] = coords[u] - (scaled[u] * dinfo->layout->u.chunk.dim[u]); /* Add point to file selection for chunk */ - if(H5S_select_elements(chunk_info->fspace, H5S_SELECT_APPEND, (size_t)1, coords_in_chunk) < 0) + if(H5S_select_elements(piece_info->fspace, H5S_SELECT_APPEND, (size_t)1, coords_in_chunk) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element") /* Increment the number of elemented selected in chunk */ - chunk_info->chunk_points++; + piece_info->piece_points++; done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__chunk_file_cb() */ +} /* end H5D__piece_file_cb */ - /*------------------------------------------------------------------------- - * Function: H5D__chunk_mem_cb + * Function: H5D__piece_mem_cb * * Purpose: Callback routine for file selection iterator. Used when - * creating selections in memory for each chunk. + * creating selections in memory for each piece. + * This was derived from H5D__chunk_mem_cb for multi-dset work. * * Return: Non-negative on success/Negative on failure * - * Programmer: Raymond Lu - * Thursday, April 10, 2003 - * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_mem_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims, const hsize_t *coords, void *_fm) +H5D__piece_mem_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, unsigned ndims, const hsize_t *coords, void *_opdata) { - H5D_chunk_map_t *fm = (H5D_chunk_map_t *)_fm; /* File<->memory chunk mapping info */ - H5D_chunk_info_t *chunk_info; /* Chunk information for current chunk */ + H5D_io_info_wrap_t *opdata = (H5D_io_info_wrap_t *)_opdata; + H5D_dset_info_t *dinfo = (H5D_dset_info_t *) opdata->dinfo; /* File<->memory chunk mapping info */ + H5D_chunk_info_t *piece_info; /* Chunk information for current piece */ hsize_t coords_in_mem[H5O_LAYOUT_NDIMS]; /* Coordinates of element in memory */ hsize_t chunk_index; /* Chunk index */ herr_t ret_value = SUCCEED; /* Return value */ @@ -2044,56 +2054,56 @@ H5D__chunk_mem_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, u FUNC_ENTER_STATIC /* Calculate the index of this chunk */ - chunk_index = H5VM_chunk_index(ndims, coords, fm->layout->u.chunk.dim, fm->layout->u.chunk.down_chunks); + chunk_index = H5VM_chunk_index(ndims, coords, dinfo->layout->u.chunk.dim, + dinfo->layout->u.chunk.down_chunks); /* Find correct chunk in file & memory skip list */ - if(chunk_index == fm->last_index) { + if(chunk_index == dinfo->last_index) { /* If the chunk index is the same as the last chunk index we used, * get the cached spaces to operate on. */ - chunk_info = fm->last_chunk_info; + piece_info = dinfo->last_piece_info; } /* end if */ else { /* If the chunk index is not the same as the last chunk index we used, - * find the chunk in the skip list. + * find the chunk in the dataset skip list. */ - /* Get the chunk node from the skip list */ - if(NULL == (chunk_info = (H5D_chunk_info_t *)H5SL_search(fm->sel_chunks, &chunk_index))) - HGOTO_ERROR(H5E_DATASPACE, H5E_NOTFOUND, FAIL, "can't locate chunk in skip list") + if(NULL == (piece_info = (H5D_chunk_info_t *)H5SL_search(dinfo->dset_sel_pieces, &chunk_index))) + HGOTO_ERROR(H5E_DATASPACE, H5E_NOTFOUND, FAIL, "can't locate piece in dataset skip list") /* Check if the chunk already has a memory space */ - if(NULL == chunk_info->mspace) { + if(NULL == piece_info->mspace) { /* Copy the template memory chunk dataspace */ - if(NULL == (chunk_info->mspace = H5S_copy(fm->mchunk_tmpl, FALSE, FALSE))) + if(NULL == (piece_info->mspace = H5S_copy(dinfo->mchunk_tmpl, FALSE, FALSE))) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space") } /* end else */ - /* Update the "last chunk seen" information */ - fm->last_index = chunk_index; - fm->last_chunk_info = chunk_info; + /* Update the "last piece seen" information */ + dinfo->last_index = chunk_index; + dinfo->last_piece_info = piece_info; } /* end else */ /* Get coordinates of selection iterator for memory */ - if(H5S_SELECT_ITER_COORDS(&fm->mem_iter, coords_in_mem) < 0) + if(H5S_SELECT_ITER_COORDS(&dinfo->mem_iter, coords_in_mem) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get iterator coordinates") /* Add point to memory selection for chunk */ - if(fm->msel_type == H5S_SEL_POINTS) { - if(H5S_select_elements(chunk_info->mspace, H5S_SELECT_APPEND, (size_t)1, coords_in_mem) < 0) + if(dinfo->msel_type == H5S_SEL_POINTS) { + if(H5S_select_elements(piece_info->mspace, H5S_SELECT_APPEND, (size_t)1, coords_in_mem) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element") } /* end if */ else { - if(H5S_hyper_add_span_element(chunk_info->mspace, fm->m_ndims, coords_in_mem) < 0) + if(H5S_hyper_add_span_element(piece_info->mspace, dinfo->m_ndims, coords_in_mem) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element") } /* end else */ /* Move memory selection iterator to next element in selection */ - if(H5S_SELECT_ITER_NEXT(&fm->mem_iter, (size_t)1) < 0) + if(H5S_SELECT_ITER_NEXT(&dinfo->mem_iter, (size_t)1) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTNEXT, FAIL, "unable to move to next iterator location") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__chunk_mem_cb() */ +} /* end H5D__piece_mem_cb() */ /*------------------------------------------------------------------------- @@ -2110,9 +2120,10 @@ done: *------------------------------------------------------------------------- */ htri_t -H5D__chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr, hbool_t write_op) +H5D__chunk_cacheable(const H5D_io_info_t *io_info, H5D_dset_info_t *dset_info, + haddr_t caddr, hbool_t write_op) { - const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */ + const H5D_t *dataset = NULL; /* Local pointer to dataset */ hbool_t has_filters = FALSE; /* Whether there are filters on the chunk or not */ htri_t ret_value = FAIL; /* Return value */ @@ -2120,6 +2131,7 @@ H5D__chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr, hbool_t write_ /* Sanity check */ HDassert(io_info); + dataset = dset_info->dset; HDassert(dataset); /* Must bring the whole chunk in if there are any filters on the chunk. @@ -2129,10 +2141,10 @@ H5D__chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr, hbool_t write_ if(dataset->shared->layout.u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) { has_filters = !H5D__chunk_is_partial_edge_chunk( - io_info->dset->shared->ndims, - io_info->dset->shared->layout.u.chunk.dim, - io_info->store->chunk.scaled, - io_info->dset->shared->curr_dims); + dataset->shared->ndims, + dataset->shared->layout.u.chunk.dim, + dset_info->store->chunk.scaled, + dataset->shared->curr_dims); } /* end if */ else has_filters = TRUE; @@ -2203,15 +2215,22 @@ done: static herr_t H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space, - H5D_chunk_map_t *fm) + H5D_dset_info_t *dset_info) { H5SL_node_t *chunk_node; /* Current node in chunk skip list */ - H5D_io_info_t nonexistent_io_info; /* "nonexistent" I/O info object */ + + H5D_io_info_t nonexistent_io_info; /* "nonexistent" I/O info object */ + H5D_dset_info_t nonexistent_dset_info; /* "nonexistent" I/O dset info object */ + H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */ + H5D_dset_info_t ctg_dset_info; /* Contiguous I/O dset info object */ H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */ + H5D_io_info_t cpt_io_info; /* Compact I/O info object */ + H5D_dset_info_t cpt_dset_info; /* Compact I/O dset info object */ H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */ hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */ + uint32_t src_accessed_bytes = 0; /* Total accessed size in a chunk */ hbool_t skip_missing_chunks = FALSE; /* Whether to skip missing chunks */ herr_t ret_value = SUCCEED; /*return value */ @@ -2220,32 +2239,39 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.rbuf); + HDassert(dset_info); + HDassert(dset_info->u.rbuf); HDassert(type_info); - HDassert(fm); + HDassert(dset_info == io_info->dsets_info); /* Set up "nonexistent" I/O info object */ HDmemcpy(&nonexistent_io_info, io_info, sizeof(nonexistent_io_info)); - nonexistent_io_info.layout_ops = *H5D_LOPS_NONEXISTENT; + HDmemcpy(&nonexistent_dset_info, dset_info, sizeof(nonexistent_dset_info)); + nonexistent_dset_info.layout_ops = *H5D_LOPS_NONEXISTENT; + nonexistent_io_info.dsets_info = &nonexistent_dset_info; /* Set up contiguous I/O info object */ HDmemcpy(&ctg_io_info, io_info, sizeof(ctg_io_info)); - ctg_io_info.store = &ctg_store; - ctg_io_info.layout_ops = *H5D_LOPS_CONTIG; + HDmemcpy(&ctg_dset_info, dset_info, sizeof(ctg_dset_info)); + ctg_dset_info.store = &ctg_store; + ctg_dset_info.layout_ops = *H5D_LOPS_CONTIG; + ctg_io_info.dsets_info = &ctg_dset_info; /* Initialize temporary contiguous storage info */ - H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, io_info->dset->shared->layout.u.chunk.size, uint32_t); + H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, dset_info->dset->shared->layout.u.chunk.size, uint32_t); /* Set up compact I/O info object */ HDmemcpy(&cpt_io_info, io_info, sizeof(cpt_io_info)); - cpt_io_info.store = &cpt_store; - cpt_io_info.layout_ops = *H5D_LOPS_COMPACT; + HDmemcpy(&cpt_dset_info, dset_info, sizeof(cpt_dset_info)); + cpt_dset_info.store = &cpt_store; + cpt_dset_info.layout_ops = *H5D_LOPS_COMPACT; + cpt_io_info.dsets_info = &cpt_dset_info; /* Initialize temporary compact storage info */ cpt_store.compact.dirty = &cpt_dirty; { - const H5O_fill_t *fill = &(io_info->dset->shared->dcpl_cache.fill); /* Fill value info */ + const H5O_fill_t *fill = &(dset_info->dset->shared->dcpl_cache.fill); /* Fill value info */ H5D_fill_value_t fill_status; /* Fill value status */ /* Check the fill value status */ @@ -2263,16 +2289,17 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, } /* Iterate through nodes in chunk skip list */ - chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); + chunk_node = H5D_CHUNK_GET_FIRST_NODE(dset_info); + while(chunk_node) { H5D_chunk_info_t *chunk_info; /* Chunk information */ H5D_chunk_ud_t udata; /* Chunk index pass-through */ /* Get the actual chunk information from the skip list node */ - chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); + chunk_info = H5D_CHUNK_GET_NODE_INFO(dset_info, chunk_node); /* Get the info for the chunk in the file */ - if(H5D__chunk_lookup(io_info->dset, io_info->md_dxpl_id, chunk_info->scaled, &udata) < 0) + if(H5D__chunk_lookup(dset_info->dset, io_info->md_dxpl_id, chunk_info->scaled, &udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") /* Sanity check */ @@ -2286,18 +2313,22 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, void *chunk = NULL; /* Pointer to locked chunk buffer */ htri_t cacheable; /* Whether the chunk is cacheable */ - /* Set chunk's [scaled] coordinates */ - io_info->store->chunk.scaled = chunk_info->scaled; + + /* Set chunk's [scaled] coordinates */ + dset_info->store->chunk.scaled = chunk_info->scaled; /* MSB ?? */ /* Determine if we should use the chunk cache */ - if((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, FALSE)) < 0) + if((cacheable = H5D__chunk_cacheable(io_info, dset_info, udata.chunk_block.offset, FALSE)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable") if(cacheable) { /* Load the chunk into cache and lock it. */ /* Compute # of bytes accessed in chunk */ H5_CHECK_OVERFLOW(type_info->src_type_size, /*From:*/ size_t, /*To:*/ uint32_t); - src_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->src_type_size; + src_accessed_bytes = chunk_info->piece_points * (uint32_t)type_info->src_type_size; + + /* Set chunk's [scaled] coordinates */ + dset_info->store->chunk.scaled = chunk_info->scaled; /* Lock the chunk into the cache */ if(NULL == (chunk = H5D__chunk_lock(io_info, &udata, FALSE, FALSE))) @@ -2323,7 +2354,7 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Perform the actual read operation */ if((io_info->io_ops.single_read)(chk_io_info, type_info, - (hsize_t)chunk_info->chunk_points, chunk_info->fspace, chunk_info->mspace) < 0) + (hsize_t)chunk_info->piece_points, chunk_info->fspace, chunk_info->mspace) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked read failed") /* Release the cache lock on the chunk. */ @@ -2332,7 +2363,7 @@ H5D__chunk_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, } /* end if */ /* Advance to next chunk in list */ - chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); + chunk_node = H5D_CHUNK_GET_NEXT_NODE(dset_info, chunk_node); } /* end while */ done: @@ -2355,12 +2386,14 @@ done: static herr_t H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space, - H5D_chunk_map_t *fm) + H5D_dset_info_t *dset_info) { H5SL_node_t *chunk_node; /* Current node in chunk skip list */ H5D_io_info_t ctg_io_info; /* Contiguous I/O info object */ + H5D_dset_info_t ctg_dset_info; /* Contiguous I/O dset info object */ H5D_storage_t ctg_store; /* Chunk storage information as contiguous dataset */ H5D_io_info_t cpt_io_info; /* Compact I/O info object */ + H5D_dset_info_t cpt_dset_info; /* Compact I/O dset info object */ H5D_storage_t cpt_store; /* Chunk storage information as compact dataset */ hbool_t cpt_dirty; /* Temporary placeholder for compact storage "dirty" flag */ uint32_t dst_accessed_bytes = 0; /* Total accessed size in a chunk */ @@ -2370,28 +2403,33 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.wbuf); + HDassert(dset_info); + HDassert(dset_info->u.wbuf); HDassert(type_info); - HDassert(fm); /* Set up contiguous I/O info object */ HDmemcpy(&ctg_io_info, io_info, sizeof(ctg_io_info)); - ctg_io_info.store = &ctg_store; - ctg_io_info.layout_ops = *H5D_LOPS_CONTIG; + HDmemcpy(&ctg_dset_info, dset_info, sizeof(ctg_dset_info)); + ctg_dset_info.store = &ctg_store; + ctg_dset_info.layout_ops = *H5D_LOPS_CONTIG; + ctg_io_info.dsets_info = &ctg_dset_info; /* Initialize temporary contiguous storage info */ - H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, io_info->dset->shared->layout.u.chunk.size, uint32_t); + H5_CHECKED_ASSIGN(ctg_store.contig.dset_size, hsize_t, dset_info->dset->shared->layout.u.chunk.size, uint32_t); /* Set up compact I/O info object */ HDmemcpy(&cpt_io_info, io_info, sizeof(cpt_io_info)); - cpt_io_info.store = &cpt_store; - cpt_io_info.layout_ops = *H5D_LOPS_COMPACT; + HDmemcpy(&cpt_dset_info, dset_info, sizeof(cpt_dset_info)); + cpt_dset_info.store = &cpt_store; + cpt_dset_info.layout_ops = *H5D_LOPS_COMPACT; + cpt_io_info.dsets_info = &cpt_dset_info; /* Initialize temporary compact storage info */ cpt_store.compact.dirty = &cpt_dirty; /* Iterate through nodes in chunk skip list */ - chunk_node = H5D_CHUNK_GET_FIRST_NODE(fm); + chunk_node = H5D_CHUNK_GET_FIRST_NODE(dset_info); + while(chunk_node) { H5D_chunk_info_t *chunk_info; /* Chunk information */ H5D_chk_idx_info_t idx_info; /* Chunked index info */ @@ -2402,10 +2440,10 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */ /* Get the actual chunk information from the skip list node */ - chunk_info = H5D_CHUNK_GET_NODE_INFO(fm, chunk_node); + chunk_info = H5D_CHUNK_GET_NODE_INFO(dset_info, chunk_node); /* Look up the chunk */ - if(H5D__chunk_lookup(io_info->dset, io_info->md_dxpl_id, chunk_info->scaled, &udata) < 0) + if(H5D__chunk_lookup(dset_info->dset, io_info->md_dxpl_id, chunk_info->scaled, &udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "error looking up chunk address") /* Sanity check */ @@ -2413,10 +2451,10 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, (!H5F_addr_defined(udata.chunk_block.offset) && udata.chunk_block.length == 0)); /* Set chunk's [scaled] coordinates */ - io_info->store->chunk.scaled = chunk_info->scaled; + dset_info->store->chunk.scaled = chunk_info->scaled; /* Determine if we should use the chunk cache */ - if((cacheable = H5D__chunk_cacheable(io_info, udata.chunk_block.offset, TRUE)) < 0) + if((cacheable = H5D__chunk_cacheable(io_info, dset_info, udata.chunk_block.offset, TRUE)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if chunk is cacheable") if(cacheable) { /* Load the chunk into cache. But if the whole chunk is written, @@ -2425,14 +2463,17 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Compute # of bytes accessed in chunk */ H5_CHECK_OVERFLOW(type_info->dst_type_size, /*From:*/ size_t, /*To:*/ uint32_t); - dst_accessed_bytes = chunk_info->chunk_points * (uint32_t)type_info->dst_type_size; + dst_accessed_bytes = chunk_info->piece_points * (uint32_t)type_info->dst_type_size; /* Determine if we will access all the data in the chunk */ if(dst_accessed_bytes != ctg_store.contig.dset_size || - (chunk_info->chunk_points * type_info->src_type_size) != ctg_store.contig.dset_size || - fm->fsel_type == H5S_SEL_POINTS) + (chunk_info->piece_points * type_info->src_type_size) != ctg_store.contig.dset_size || + dset_info->fsel_type == H5S_SEL_POINTS) entire_chunk = FALSE; + /* Set chunk's [scaled] coordinates */ + dset_info->store->chunk.scaled = chunk_info->scaled; + /* Lock the chunk into the cache */ if(NULL == (chunk = H5D__chunk_lock(io_info, &udata, entire_chunk, FALSE))) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk") @@ -2447,14 +2488,14 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* If the chunk hasn't been allocated on disk, do so now. */ if(!H5F_addr_defined(udata.chunk_block.offset)) { /* Compose chunked index info struct */ - idx_info.f = io_info->dset->oloc.file; + idx_info.f = dset_info->dset->oloc.file; idx_info.dxpl_id = io_info->md_dxpl_id; - idx_info.pline = &(io_info->dset->shared->dcpl_cache.pline); - idx_info.layout = &(io_info->dset->shared->layout.u.chunk); - idx_info.storage = &(io_info->dset->shared->layout.storage.u.chunk); + idx_info.pline = &(dset_info->dset->shared->dcpl_cache.pline); + idx_info.layout = &(dset_info->dset->shared->layout.u.chunk); + idx_info.storage = &(dset_info->dset->shared->layout.storage.u.chunk); /* Set up the size of chunk for user data */ - udata.chunk_block.length = io_info->dset->shared->layout.u.chunk.size; + udata.chunk_block.length = dset_info->dset->shared->layout.u.chunk.size; /* Allocate the chunk */ if(H5D__chunk_file_alloc(&idx_info, NULL, &udata.chunk_block, &need_insert, chunk_info->scaled) < 0) @@ -2465,7 +2506,7 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "chunk address isn't defined") /* Cache the new chunk information */ - H5D__chunk_cinfo_cache_update(&io_info->dset->shared->cache.chunk.last, &udata); + H5D__chunk_cinfo_cache_update(&dset_info->dset->shared->cache.chunk.last, &udata); } /* end if */ /* Set up the storage address information for this chunk */ @@ -2478,9 +2519,13 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, chk_io_info = &ctg_io_info; } /* end else */ + HDassert(TRUE == H5P_isa_class(io_info->md_dxpl_id, H5P_DATASET_XFER)); + HDassert(TRUE == H5P_isa_class(ctg_io_info.md_dxpl_id, H5P_DATASET_XFER)); + HDassert(TRUE == H5P_isa_class(chk_io_info->md_dxpl_id, H5P_DATASET_XFER)); + /* Perform the actual write operation */ if((io_info->io_ops.single_write)(chk_io_info, type_info, - (hsize_t)chunk_info->chunk_points, chunk_info->fspace, chunk_info->mspace) < 0) + (hsize_t)chunk_info->piece_points, chunk_info->fspace, chunk_info->mspace) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "chunked write failed") /* Release the cache lock on the chunk, or insert chunk into index. */ @@ -2489,19 +2534,20 @@ H5D__chunk_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk") } /* end if */ else { - if(need_insert && io_info->dset->shared->layout.storage.u.chunk.ops->insert) - if((io_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, NULL) < 0) + if(need_insert && dset_info->dset->shared->layout.storage.u.chunk.ops->insert) + if((dset_info->dset->shared->layout.storage.u.chunk.ops->insert)(&idx_info, &udata, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "unable to insert chunk addr into index") } /* end else */ /* Advance to next chunk in list */ - chunk_node = H5D_CHUNK_GET_NEXT_NODE(fm, chunk_node); + chunk_node = H5D_CHUNK_GET_NEXT_NODE(dset_info, chunk_node); } /* end while */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5D__chunk_write() */ + /*------------------------------------------------------------------------- * Function: H5D__chunk_flush @@ -2548,56 +2594,57 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__chunk_flush() */ - /*------------------------------------------------------------------------- - * Function: H5D__chunk_io_term + * Function: H5D__piece_io_term * * Purpose: Destroy I/O operation information. * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Saturday, May 17, 2003 - * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ -static herr_t -H5D__chunk_io_term(const H5D_chunk_map_t *fm) +herr_t +H5D__piece_io_term(H5D_io_info_t *io_info, H5D_dset_info_t *di) { herr_t ret_value = SUCCEED; /*return value */ FUNC_ENTER_STATIC /* Single element I/O vs. multiple element I/O cleanup */ - if(fm->use_single) { + if(di->use_single) { /* Sanity checks */ - HDassert(fm->sel_chunks == NULL); - HDassert(fm->single_chunk_info); - HDassert(fm->single_chunk_info->fspace_shared); - HDassert(fm->single_chunk_info->mspace_shared); + HDassert(di->dset_sel_pieces == NULL); + HDassert(di->last_piece_info == NULL); + HDassert(di->single_chunk_info); + HDassert(di->single_chunk_info->fspace_shared); + HDassert(di->single_chunk_info->mspace_shared); /* Reset the selection for the single element I/O */ - H5S_select_all(fm->single_space, TRUE); + H5S_select_all(di->single_space, TRUE); } /* end if */ else { - /* Release the nodes on the list of selected chunks */ - if(fm->sel_chunks) - if(H5SL_free(fm->sel_chunks, H5D__free_chunk_info, NULL) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTNEXT, FAIL, "can't iterate over chunks") + /* Release the nodes on the list of selected pieces, or the last (only) + * piece if the skiplist is not available */ + if(di->dset_sel_pieces) { + if(H5SL_free(di->dset_sel_pieces, H5D__free_piece_info, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't free dataset skip list") + } /* end if */ + else if(di->last_piece_info) { + if(H5D__free_piece_info(di->last_piece_info, NULL, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't free piece info") + di->last_piece_info = NULL; + } /* end if */ } /* end else */ - /* Free the memory chunk dataspace template */ - if(fm->mchunk_tmpl) - if(H5S_close(fm->mchunk_tmpl) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory chunk dataspace template") -#ifdef H5_HAVE_PARALLEL - if(fm->select_chunk) - H5MM_xfree(fm->select_chunk); -#endif /* H5_HAVE_PARALLEL */ + /* Free the memory piece dataspace template */ + if(di->mchunk_tmpl) + if(H5S_close(di->mchunk_tmpl) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory piece dataspace template") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__chunk_io_term() */ +} /* end H5D__piece_io_term() */ /*------------------------------------------------------------------------- @@ -3441,7 +3488,7 @@ static void * H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t relax, hbool_t prev_unfilt_chunk) { - const H5D_t *dset = io_info->dset; /* Local pointer to the dataset info */ + const H5D_t *dset = io_info->dsets_info[0].dset; /* Local pointer to the dataset info */ const H5O_pline_t *pline = &(dset->shared->dcpl_cache.pline); /* I/O pipeline info - always equal to the pline passed to H5D__chunk_mem_alloc */ const H5O_pline_t *old_pline = pline; /* Old pipeline, i.e. pipeline used to read the chunk */ const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset layout */ @@ -3459,7 +3506,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, HDassert(io_info); HDassert(io_info->dxpl_cache); - HDassert(io_info->store); + HDassert(io_info->dsets_info[0].store); HDassert(udata); HDassert(dset); HDassert(TRUE == H5P_isa_class(io_info->md_dxpl_id, H5P_DATASET_XFER)); @@ -3486,7 +3533,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, /* Make sure this is the right chunk */ for(u = 0; u < layout->u.chunk.ndims - 1; u++) - HDassert(io_info->store->chunk.scaled[u] == ent->scaled[u]); + HDassert(io_info->dsets_info[0].store->chunk.scaled[u] == ent->scaled[u]); } #endif /* NDEBUG */ @@ -3605,9 +3652,9 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, else if(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) { /* Check if this is an edge chunk */ - if(H5D__chunk_is_partial_edge_chunk(io_info->dset->shared->ndims, - layout->u.chunk.dim, io_info->store->chunk.scaled, - io_info->dset->shared->curr_dims)) { + if(H5D__chunk_is_partial_edge_chunk(dset->shared->ndims, + layout->u.chunk.dim, io_info->dsets_info[0].store->chunk.scaled, + dset->shared->curr_dims)) { /* Disable the filters for both writing and reading */ disable_filters = TRUE; old_pline = NULL; @@ -3722,17 +3769,17 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, /* See if the chunk can be cached */ if(rdcc->nslots > 0 && chunk_size <= rdcc->nbytes_max) { /* Calculate the index */ - udata->idx_hint = H5D__chunk_hash_val(io_info->dset->shared, udata->common.scaled); + udata->idx_hint = H5D__chunk_hash_val(dset->shared, udata->common.scaled); /* Add the chunk to the cache only if the slot is not already locked */ ent = rdcc->slot[udata->idx_hint]; if(!ent || !ent->locked) { /* Preempt enough things from the cache to make room */ if(ent) { - if(H5D__chunk_cache_evict(io_info->dset, io_info->md_dxpl_id, io_info->dxpl_cache, ent, TRUE) < 0) + if(H5D__chunk_cache_evict(io_info->dsets_info[0].dset, io_info->md_dxpl_id, io_info->dxpl_cache, ent, TRUE) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL, "unable to preempt chunk from cache") } /* end if */ - if(H5D__chunk_cache_prune(io_info->dset, io_info->md_dxpl_id, io_info->dxpl_cache, chunk_size) < 0) + if(H5D__chunk_cache_prune(io_info->dsets_info[0].dset, io_info->md_dxpl_id, io_info->dxpl_cache, chunk_size) < 0) HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL, "unable to preempt chunk(s) from cache") /* Create a new entry */ @@ -3833,11 +3880,12 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, - hbool_t dirty, void *chunk, uint32_t naccessed) +H5D__chunk_unlock(const H5D_io_info_t *io_info, + const H5D_chunk_ud_t *udata, hbool_t dirty, void *chunk, uint32_t naccessed) { - const H5O_layout_t *layout = &(io_info->dset->shared->layout); /* Dataset layout */ - const H5D_rdcc_t *rdcc = &(io_info->dset->shared->cache.chunk); + const H5O_layout_t *layout = &(io_info->dsets_info[0].dset->shared->layout); /* Dataset layout */ + const H5D_rdcc_t *rdcc = &(io_info->dsets_info[0].dset->shared->cache.chunk); + const H5D_t *dset = io_info->dsets_info[0].dset; /* Local pointer to the dataset info */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC @@ -3862,8 +3910,8 @@ H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, else if(layout->u.chunk.flags & H5O_LAYOUT_CHUNK_DONT_FILTER_PARTIAL_BOUND_CHUNKS) { /* Check if the chunk is an edge chunk, and disable filters if so */ is_unfiltered_edge_chunk = H5D__chunk_is_partial_edge_chunk( - io_info->dset->shared->ndims, layout->u.chunk.dim, - io_info->store->chunk.scaled, io_info->dset->shared->curr_dims); + dset->shared->ndims, layout->u.chunk.dim, + io_info->dsets_info[0].store->chunk.scaled, dset->shared->curr_dims); } /* end if */ if(dirty) { @@ -3882,13 +3930,13 @@ H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, fake_ent.chunk_block.length = udata->chunk_block.length; fake_ent.chunk = (uint8_t *)chunk; - if(H5D__chunk_flush_entry(io_info->dset, io_info->md_dxpl_id, io_info->dxpl_cache, &fake_ent, TRUE) < 0) + if(H5D__chunk_flush_entry(io_info->dsets_info[0].dset, io_info->md_dxpl_id, io_info->dxpl_cache, &fake_ent, TRUE) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer") } /* end if */ else { if(chunk) chunk = H5D__chunk_mem_xfree(chunk, (is_unfiltered_edge_chunk ? NULL - : &(io_info->dset->shared->dcpl_cache.pline))); + : &(io_info->dsets_info[0].dset->shared->dcpl_cache.pline))); } /* end else */ } /* end if */ else { @@ -4489,6 +4537,7 @@ H5D__chunk_update_old_edge_chunks(H5D_t *dset, hid_t dxpl_id, hsize_t old_dim[]) H5D_io_info_t chk_io_info; /* Chunked I/O info object */ H5D_chunk_ud_t chk_udata; /* User data for locking chunk */ H5D_storage_t chk_store; /* Chunk storage information */ + H5D_dset_info_t chk_dset_info; /* Chunked I/O dset info object */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ void *chunk; /* The file chunk */ @@ -4534,7 +4583,16 @@ H5D__chunk_update_old_edge_chunks(H5D_t *dset, hid_t dxpl_id, hsize_t old_dim[]) * Note that we only need to set chunk_offset once, as the array's address * will never change. */ chk_store.chunk.scaled = chunk_sc; - H5D_BUILD_IO_INFO_RD(&chk_io_info, dset, dxpl_cache, dxpl_id, H5AC_rawdata_dxpl_id, &chk_store, NULL); + + chk_io_info.dxpl_cache = dxpl_cache; + chk_io_info.md_dxpl_id = dxpl_id; + chk_io_info.op_type = H5D_IO_OP_READ; + chk_io_info.raw_dxpl_id = H5AC_rawdata_dxpl_id; + + chk_dset_info.dset = dset; + chk_dset_info.store = &chk_store; + chk_dset_info.u.rbuf = NULL; + chk_io_info.dsets_info = &chk_dset_info; /* * Determine the edges of the dataset which need to be modified @@ -4808,7 +4866,7 @@ static herr_t H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk) { const H5D_io_info_t *io_info = udata->io_info; /* Local pointer to I/O info */ - const H5D_t *dset = io_info->dset; /* Local pointer to the dataset info */ + const H5D_t *dset = io_info->dsets_info[0].dset; /* Local pointer to the dataset info */ const H5O_layout_t *layout = &(dset->shared->layout); /* Dataset's layout */ unsigned rank = udata->common.layout->ndims - 1; /* Dataset rank */ const hsize_t *scaled = udata->common.scaled; /* Scaled chunk offset */ @@ -5028,6 +5086,7 @@ H5D__chunk_prune_by_extent(H5D_t *dset, hid_t dxpl_id, const hsize_t *old_dim) hbool_t new_unfilt_dim[H5O_LAYOUT_NDIMS]; /* Whether the plane of edge chunks in this dimension are newly unfiltered */ H5D_chk_idx_info_t idx_info; /* Chunked index info */ H5D_io_info_t chk_io_info; /* Chunked I/O info object */ + H5D_dset_info_t chk_dset_info; /* Chunked I/O dset info object */ H5D_storage_t chk_store; /* Chunk storage information */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ @@ -5104,6 +5163,11 @@ H5D__chunk_prune_by_extent(H5D_t *dset, hid_t dxpl_id, const hsize_t *old_dim) chk_store.chunk.scaled = scaled; H5D_BUILD_IO_INFO_RD(&chk_io_info, dset, dxpl_cache, dxpl_id, H5AC_rawdata_dxpl_id, &chk_store, NULL); + chk_dset_info.dset = dset; + chk_dset_info.store = &chk_store; + chk_dset_info.u.rbuf = NULL; + chk_io_info.dsets_info = &chk_dset_info; + /* Compose chunked index info struct */ idx_info.f = dset->oloc.file; idx_info.dxpl_id = dxpl_id; @@ -5397,7 +5461,7 @@ herr_t H5D__chunk_addrmap(const H5D_io_info_t *io_info, haddr_t chunk_addr[]) { H5D_chk_idx_info_t idx_info; /* Chunked index info */ - const H5D_t *dset = io_info->dset; /* Local pointer to dataset info */ + const H5D_t *dset = io_info->dsets_info[0].dset; /* Local pointer to dataset info */ H5D_chunk_it_ud2_t udata; /* User data for iteration callback */ H5O_storage_chunk_t *sc = &(dset->shared->layout.storage.u.chunk); herr_t ret_value = SUCCEED; /* Return value */ @@ -6487,8 +6551,8 @@ H5D__nonexistent_readvv(const H5D_io_info_t *io_info, HDassert(mem_off_arr); /* Set up user data for H5VM_opvv() */ - udata.rbuf = (unsigned char *)io_info->u.rbuf; - udata.dset = io_info->dset; + udata.rbuf = (unsigned char *)io_info->dsets_info[0].u.rbuf; + udata.dset = io_info->dsets_info[0].dset; udata.dxpl_id = io_info->md_dxpl_id; /* Call generic sequence operation routine */ diff --git a/src/H5Dcompact.c b/src/H5Dcompact.c index 041d28f..4bfb0f5 100644 --- a/src/H5Dcompact.c +++ b/src/H5Dcompact.c @@ -58,9 +58,9 @@ /* Layout operation callbacks */ static herr_t H5D__compact_construct(H5F_t *f, H5D_t *dset); static hbool_t H5D__compact_is_space_alloc(const H5O_storage_t *storage); -static herr_t H5D__compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t *cm); +static herr_t H5D__compact_io_init(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, + const H5S_t *mem_space, H5D_dset_info_t *dinfo); static ssize_t H5D__compact_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_size_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[]); @@ -249,14 +249,14 @@ H5D__compact_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage) *------------------------------------------------------------------------- */ static herr_t -H5D__compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, +H5D__compact_io_init(H5D_io_info_t H5_ATTR_UNUSED *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space, - H5D_chunk_map_t H5_ATTR_UNUSED *cm) + H5D_dset_info_t *dinfo) { FUNC_ENTER_STATIC_NOERR - io_info->store->compact.buf = io_info->dset->shared->layout.storage.u.compact.buf; - io_info->store->compact.dirty = &io_info->dset->shared->layout.storage.u.compact.dirty; + dinfo->store->compact.buf = dinfo->dset->shared->layout.storage.u.compact.buf; + dinfo->store->compact.dirty = &dinfo->dset->shared->layout.storage.u.compact.dirty; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__compact_io_init() */ @@ -292,7 +292,9 @@ H5D__compact_readvv(const H5D_io_info_t *io_info, HDassert(io_info); /* Use the vectorized memory copy routine to do actual work */ - if((ret_value = H5VM_memcpyvv(io_info->u.rbuf, mem_max_nseq, mem_curr_seq, mem_size_arr, mem_offset_arr, io_info->store->compact.buf, dset_max_nseq, dset_curr_seq, dset_size_arr, dset_offset_arr)) < 0) + if((ret_value = H5VM_memcpyvv(io_info->dsets_info[0].u.rbuf, mem_max_nseq, mem_curr_seq, + mem_size_arr, mem_offset_arr, io_info->dsets_info[0].store->compact.buf, + dset_max_nseq, dset_curr_seq, dset_size_arr, dset_offset_arr)) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed") done: @@ -333,11 +335,14 @@ H5D__compact_writevv(const H5D_io_info_t *io_info, HDassert(io_info); /* Use the vectorized memory copy routine to do actual work */ - if((ret_value = H5VM_memcpyvv(io_info->store->compact.buf, dset_max_nseq, dset_curr_seq, dset_size_arr, dset_offset_arr, io_info->u.wbuf, mem_max_nseq, mem_curr_seq, mem_size_arr, mem_offset_arr)) < 0) + if((ret_value = H5VM_memcpyvv(io_info->dsets_info[0].store->compact.buf, dset_max_nseq, + dset_curr_seq, dset_size_arr, dset_offset_arr, + io_info->dsets_info[0].u.wbuf, mem_max_nseq, mem_curr_seq, + mem_size_arr, mem_offset_arr)) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed") /* Mark the compact dataset's buffer as dirty */ - *io_info->store->compact.dirty = TRUE; + *io_info->dsets_info[0].store->compact.dirty = TRUE; done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Dcontig.c b/src/H5Dcontig.c index 86de017..7c68987 100644 --- a/src/H5Dcontig.c +++ b/src/H5Dcontig.c @@ -97,9 +97,8 @@ typedef struct H5D_contig_writevv_ud_t { static herr_t H5D__contig_construct(H5F_t *f, H5D_t *dset); static herr_t H5D__contig_init(H5F_t *f, hid_t dxpl_id, const H5D_t *dset, hid_t dapl_id); -static herr_t H5D__contig_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t *cm); +static herr_t H5D__contig_io_init(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, H5D_dset_info_t *dinfo); static ssize_t H5D__contig_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); @@ -126,13 +125,13 @@ const H5D_layout_ops_t H5D_LOPS_CONTIG[1] = {{ H5D__contig_read, H5D__contig_write, #ifdef H5_HAVE_PARALLEL - H5D__contig_collective_read, - H5D__contig_collective_write, + H5D__collective_read, + H5D__collective_write, #endif /* H5_HAVE_PARALLEL */ H5D__contig_readvv, H5D__contig_writevv, H5D__contig_flush, - NULL, + H5D__piece_io_term, NULL }}; @@ -147,6 +146,8 @@ H5FL_BLK_DEFINE(sieve_buf); /* Declare extern the free list to manage blocks of type conversion data */ H5FL_BLK_EXTERN(type_conv); +/* Declare extern the free list to manage the H5D_chunk_info_t struct */ +H5FL_EXTERN(H5D_chunk_info_t); /*------------------------------------------------------------------------- @@ -198,6 +199,7 @@ H5D__contig_fill(const H5D_io_info_t *io_info) { const H5D_t *dset = io_info->dset; /* the dataset pointer */ H5D_io_info_t ioinfo; /* Dataset I/O info */ + H5D_dset_info_t dset_info; /* Dset info */ H5D_storage_t store; /* Union of storage info for dataset */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ @@ -269,7 +271,15 @@ H5D__contig_fill(const H5D_io_info_t *io_info) offset = 0; /* Simple setup for dataset I/O info struct */ - H5D_BUILD_IO_INFO_WRT(&ioinfo, dset, dxpl_cache, H5AC_ind_read_dxpl_id, raw_dxpl_id, &store, fb_info.fill_buf); + ioinfo.dxpl_cache = dxpl_cache; + ioinfo.op_type = H5D_IO_OP_WRITE; + ioinfo.md_dxpl_id = H5AC_ind_read_dxpl_id; + ioinfo.raw_dxpl_id = raw_dxpl_id; + + dset_info.dset = (H5D_t *)dset; + dset_info.store = &store; + dset_info.u.wbuf = fb_info.fill_buf; + ioinfo.dsets_info = &dset_info; /* * Fill the entire current extent with the fill value. We can do @@ -402,7 +412,7 @@ H5D__contig_construct(H5F_t *f, H5D_t *dset) /* * The maximum size of the dataset cannot exceed the storage size. - * Also, only the slowest varying dimension of a simple data space + * Also, only the slowest varying dimension of a simple dataspace * can be extendible (currently only for external data storage). */ @@ -554,22 +564,205 @@ H5D__contig_is_space_alloc(const H5O_storage_t *storage) * * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * Thursday, March 20, 2008 - * + * Programmer: Jonathan Kim *------------------------------------------------------------------------- */ static herr_t -H5D__contig_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, - hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space, - H5D_chunk_map_t H5_ATTR_UNUSED *cm) +H5D__contig_io_init(H5D_io_info_t *io_info, + const H5D_type_info_t H5_ATTR_UNUSED *type_info, hsize_t nelmts, + const H5S_t *file_space, const H5S_t *mem_space, H5D_dset_info_t *dinfo) { - FUNC_ENTER_STATIC_NOERR + H5D_t *dataset = dinfo->dset; /* Local pointer to dataset info */ + + hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */ + htri_t file_space_normalized = FALSE; /* File dataspace was normalized */ + + int sm_ndims; /* The number of dimensions of the memory buffer's dataspace (signed) */ + int sf_ndims; /* The number of dimensions of the file dataspace (signed) */ + H5S_class_t fsclass_type; /* file space class type */ + H5S_sel_type fsel_type; /* file space selection type */ + hbool_t sel_hyper_flag; + + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + dinfo->store->contig.dset_addr = dataset->shared->layout.storage.u.contig.addr; + dinfo->store->contig.dset_size = dataset->shared->layout.storage.u.contig.size; + + /* Get layout for dataset */ + dinfo->layout = &(dataset->shared->layout); + /* num of element selected */ + dinfo->nelmts = nelmts; + + /* Check if the memory space is scalar & make equivalent memory space */ + if((sm_ndims = H5S_GET_EXTENT_NDIMS(mem_space)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number") + /* Set the number of dimensions for the memory dataspace */ + H5_CHECKED_ASSIGN(dinfo->m_ndims, unsigned, sm_ndims, int); + + /* Get dim number and dimensionality for each dataspace */ + if((sf_ndims = H5S_GET_EXTENT_NDIMS(file_space)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimension number") + /* Set the number of dimensions for the file dataspace */ + H5_CHECKED_ASSIGN(dinfo->f_ndims, unsigned, sf_ndims, int); + + if(H5S_get_simple_extent_dims(file_space, dinfo->f_dims, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimensionality") + + /* Normalize hyperslab selections by adjusting them by the offset */ + /* (It might be worthwhile to normalize both the file and memory dataspaces + * before any (contiguous, chunked, etc) file I/O operation, in order to + * speed up hyperslab calculations by removing the extra checks and/or + * additions involving the offset and the hyperslab selection -QAK) + */ + if((file_space_normalized = H5S_hyper_normalize_offset((H5S_t *)file_space, old_offset)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") + + /* Initialize "last chunk" information */ + dinfo->last_index = (hsize_t)-1; + dinfo->last_piece_info = NULL; + + /* Point at the dataspaces */ + dinfo->file_space = file_space; + dinfo->mem_space = mem_space; + + /* Only need single skip list point over multiple read/write IO + * and multiple dsets until H5D_close. Thus check both + * since io_info->sel_pieces only lives single write/read IO, + * even cache.sel_pieces lives until Dclose */ + if(NULL == dataset->shared->cache.sel_pieces && + NULL == io_info->sel_pieces) { + if(NULL == (dataset->shared->cache.sel_pieces = H5SL_create(H5SL_TYPE_HADDR, NULL))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for piece selections") + + /* keep the skip list in cache, so do not need to recreate until close */ + io_info->sel_pieces = dataset->shared->cache.sel_pieces; + } /* end if */ + + /* this is need when multiple write/read occurs on the same dsets, + * just pass the previously created pointer */ + if (NULL == io_info->sel_pieces) + io_info->sel_pieces = dataset->shared->cache.sel_pieces; + + HDassert(io_info->sel_pieces); + + /* We are not using single element mode */ + dinfo->use_single = FALSE; + + /* Get type of space class on disk */ + if((fsclass_type = H5S_GET_EXTENT_TYPE(file_space)) < H5S_SCALAR) + HGOTO_ERROR(H5E_FSPACE, H5E_BADTYPE, FAIL, "unable to get fspace class type") + + /* Get type of selection on disk & in memory */ + if((fsel_type = H5S_GET_SELECT_TYPE(file_space)) < H5S_SEL_NONE) + HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") + if((dinfo->msel_type = H5S_GET_SELECT_TYPE(mem_space)) < H5S_SEL_NONE) + HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") + + /* if class type is scalar or null for contiguous dset */ + if(fsclass_type == H5S_SCALAR || fsclass_type == H5S_NULL) + sel_hyper_flag = FALSE; + /* if class type is H5S_SIMPLE & if selection is NONE or POINTS */ + else if(fsel_type == H5S_SEL_POINTS || fsel_type == H5S_SEL_NONE) + sel_hyper_flag = FALSE; + else + sel_hyper_flag = TRUE; + + /* if selected elements exist */ + if (dinfo->nelmts) { + unsigned u; + H5D_chunk_info_t *new_piece_info; /* piece information to insert into skip list */ + + /* Get copy of dset file_space, so it can be changed temporarily + * purpose + * This tmp_fspace allows multiple write before close dset */ + H5S_t *tmp_fspace; /* Temporary file dataspace */ + /* Create "temporary" chunk for selection operations (copy file space) */ + if(NULL == (tmp_fspace = H5S_copy(dinfo->file_space, TRUE, FALSE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") + + /* Actions specific to hyperslab selections */ + if(sel_hyper_flag) { + /* Sanity check */ + HDassert(dinfo->f_ndims > 0); + + /* Make certain selections are stored in span tree form (not "optimized hyperslab" or "all") */ + if(H5S_hyper_convert(tmp_fspace) < 0) { + (void)H5S_close(tmp_fspace); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to convert selection to span trees") + } /* end if */ + } /* end if */ + + /* Add temporary chunk to the list of pieces */ + /* collect piece_info into Skip List */ + /* Allocate the file & memory chunk information */ + if (NULL==(new_piece_info = H5FL_MALLOC (H5D_chunk_info_t))) { + (void)H5S_close(tmp_fspace); + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") + } /* end if */ + + /* Set the piece index */ + new_piece_info->index = 0; + + /* Set the file chunk dataspace */ + new_piece_info->fspace = tmp_fspace; + new_piece_info->fspace_shared = FALSE; + + /* Set the memory chunk dataspace */ + /* same as one chunk, just use dset mem space */ + new_piece_info->mspace = mem_space; + + /* set true for sharing mem space with dset, which means + * fspace gets free by applicaton H5Sclose(), and + * doesn't require providing layout_ops.io_term() for H5D_LOPS_CONTIG. + */ + new_piece_info->mspace_shared = TRUE; + + /* Copy the piece's coordinates */ + for(u = 0; u < dinfo->f_ndims; u++) + new_piece_info->scaled[u] = 0; + new_piece_info->scaled[dinfo->f_ndims] = 0; + + /* make connection to related dset info from this piece_info */ + new_piece_info->dset_info = dinfo; + + /* get dset file address for piece */ + new_piece_info->faddr = dinfo->dset->shared->layout.storage.u.contig.addr; + + /* Save piece to last_piece_info so it is freed at the end of the + * operation */ + dinfo->last_piece_info = new_piece_info; + + /* insert piece info */ + if(H5SL_insert(io_info->sel_pieces, new_piece_info, &new_piece_info->faddr) < 0) { + /* mimic H5D__free_piece_info */ + H5S_select_all(new_piece_info->fspace, TRUE); + H5FL_FREE(H5D_chunk_info_t, new_piece_info); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into skip list") + } /* end if */ + H5_CHECKED_ASSIGN(new_piece_info->piece_points, uint32_t, nelmts, hssize_t); + + /* only scratch for this dset */ + /* Clean hyperslab span's "scratch" information */ + if(sel_hyper_flag) + if(H5S_hyper_reset_scratch(new_piece_info->fspace) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info") + } /* end if */ + +done: + if(ret_value < 0) { + if(H5D__piece_io_term(io_info, dinfo) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release chunk mapping") + } /* end if */ - io_info->store->contig.dset_addr = io_info->dset->shared->layout.storage.u.contig.addr; - io_info->store->contig.dset_size = io_info->dset->shared->layout.storage.u.contig.size; + if(file_space_normalized) { + /* (Casting away const OK -QAK) */ + if(H5S_hyper_denormalize_offset((H5S_t *)file_space, old_offset) < 0) + HDONE_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to normalize dataspace by offset") + } /* end if */ - FUNC_LEAVE_NOAPI(SUCCEED) + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__contig_io_init() */ @@ -588,7 +781,7 @@ H5D__contig_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_ herr_t H5D__contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t H5_ATTR_UNUSED *fm) + H5D_dset_info_t *dinfo) { herr_t ret_value = SUCCEED; /*return value */ @@ -596,11 +789,13 @@ H5D__contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.rbuf); + HDassert(dinfo->u.rbuf); HDassert(type_info); HDassert(mem_space); HDassert(file_space); + io_info->dset = io_info->dsets_info[0].dset; + /* Read data */ if((io_info->io_ops.single_read)(io_info, type_info, nelmts, file_space, mem_space) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "contiguous read failed") @@ -625,7 +820,7 @@ done: herr_t H5D__contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t H5_ATTR_UNUSED *fm) + H5D_dset_info_t *dinfo) { herr_t ret_value = SUCCEED; /*return value */ @@ -633,11 +828,13 @@ H5D__contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.wbuf); + HDassert(dinfo->u.wbuf); HDassert(type_info); HDassert(mem_space); HDassert(file_space); + io_info->dset = io_info->dsets_info[0].dset; + /* Write data */ if((io_info->io_ops.single_write)(io_info, type_info, nelmts, file_space, mem_space) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "contiguous write failed") @@ -911,6 +1108,7 @@ H5D__contig_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) { + H5D_dset_info_t dset_info; ssize_t ret_value = -1; /* Return value */ FUNC_ENTER_STATIC @@ -924,15 +1122,17 @@ H5D__contig_readvv(const H5D_io_info_t *io_info, HDassert(mem_len_arr); HDassert(mem_off_arr); + dset_info = io_info->dsets_info[0]; + /* Check if data sieving is enabled */ - if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_DATA_SIEVE)) { + if(H5F_HAS_FEATURE(dset_info.dset->oloc.file, H5FD_FEAT_DATA_SIEVE)) { H5D_contig_readvv_sieve_ud_t udata; /* User data for H5VM_opvv() operator */ /* Set up user data for H5VM_opvv() */ - udata.file = io_info->dset->oloc.file; - udata.dset_contig = &(io_info->dset->shared->cache.contig); - udata.store_contig = &(io_info->store->contig); - udata.rbuf = (unsigned char *)io_info->u.rbuf; + udata.file = dset_info.dset->oloc.file; + udata.dset_contig = &(dset_info.dset->shared->cache.contig); + udata.store_contig = &(dset_info.store->contig); + udata.rbuf = (unsigned char *)dset_info.u.rbuf; udata.dxpl_id = io_info->raw_dxpl_id; /* Call generic sequence operation routine */ @@ -945,9 +1145,9 @@ H5D__contig_readvv(const H5D_io_info_t *io_info, H5D_contig_readvv_ud_t udata; /* User data for H5VM_opvv() operator */ /* Set up user data for H5VM_opvv() */ - udata.file = io_info->dset->oloc.file; - udata.dset_addr = io_info->store->contig.dset_addr; - udata.rbuf = (unsigned char *)io_info->u.rbuf; + udata.file = dset_info.dset->oloc.file; + udata.dset_addr = dset_info.store->contig.dset_addr; + udata.rbuf = (unsigned char *)dset_info.u.rbuf; udata.dxpl_id = io_info->raw_dxpl_id; /* Call generic sequence operation routine */ @@ -1237,6 +1437,7 @@ H5D__contig_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) { + H5D_dset_info_t dset_info; ssize_t ret_value = -1; /* Return value (Size of sequence in bytes) */ FUNC_ENTER_STATIC @@ -1250,15 +1451,17 @@ H5D__contig_writevv(const H5D_io_info_t *io_info, HDassert(mem_len_arr); HDassert(mem_off_arr); + dset_info = io_info->dsets_info[0]; + /* Check if data sieving is enabled */ - if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_DATA_SIEVE)) { + if(H5F_HAS_FEATURE(dset_info.dset->oloc.file, H5FD_FEAT_DATA_SIEVE)) { H5D_contig_writevv_sieve_ud_t udata; /* User data for H5VM_opvv() operator */ /* Set up user data for H5VM_opvv() */ - udata.file = io_info->dset->oloc.file; - udata.dset_contig = &(io_info->dset->shared->cache.contig); - udata.store_contig = &(io_info->store->contig); - udata.wbuf = (const unsigned char *)io_info->u.wbuf; + udata.file = dset_info.dset->oloc.file; + udata.dset_contig = &(dset_info.dset->shared->cache.contig); + udata.store_contig = &(dset_info.store->contig); + udata.wbuf = (const unsigned char *)dset_info.u.wbuf; udata.dxpl_id = io_info->raw_dxpl_id; /* Call generic sequence operation routine */ @@ -1271,9 +1474,9 @@ H5D__contig_writevv(const H5D_io_info_t *io_info, H5D_contig_writevv_ud_t udata; /* User data for H5VM_opvv() operator */ /* Set up user data for H5VM_opvv() */ - udata.file = io_info->dset->oloc.file; - udata.dset_addr = io_info->store->contig.dset_addr; - udata.wbuf = (const unsigned char *)io_info->u.wbuf; + udata.file = dset_info.dset->oloc.file; + udata.dset_addr = dset_info.store->contig.dset_addr; + udata.wbuf = (const unsigned char *)dset_info.u.wbuf; udata.dxpl_id = io_info->raw_dxpl_id; /* Call generic sequence operation routine */ diff --git a/src/H5Defl.c b/src/H5Defl.c index ebe7689..a9ded9b 100644 --- a/src/H5Defl.c +++ b/src/H5Defl.c @@ -65,9 +65,9 @@ typedef struct H5D_efl_writevv_ud_t { /* Layout operation callbacks */ static herr_t H5D__efl_construct(H5F_t *f, H5D_t *dset); -static herr_t H5D__efl_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t *cm); +static herr_t H5D__efl_io_init(H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, + const H5S_t *mem_space, H5D_dset_info_t *dinfo); static ssize_t H5D__efl_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); @@ -220,13 +220,13 @@ H5D__efl_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage) *------------------------------------------------------------------------- */ static herr_t -H5D__efl_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, +H5D__efl_io_init(H5D_io_info_t H5_ATTR_UNUSED *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, hsize_t H5_ATTR_UNUSED nelmts, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space, - H5D_chunk_map_t H5_ATTR_UNUSED *cm) + H5D_dset_info_t *dinfo) { FUNC_ENTER_STATIC_NOERR - HDmemcpy(&io_info->store->efl, &(io_info->dset->shared->dcpl_cache.efl), sizeof(H5O_efl_t)); + HDmemcpy(&dinfo->store->efl, &(dinfo->dset->shared->dcpl_cache.efl), sizeof(H5O_efl_t)); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__efl_io_init() */ @@ -472,8 +472,8 @@ H5D__efl_readvv(const H5D_io_info_t *io_info, /* Check args */ HDassert(io_info); - HDassert(io_info->store->efl.nused > 0); - HDassert(io_info->u.rbuf); + HDassert(io_info->dsets_info[0].store->efl.nused > 0); + HDassert(io_info->dsets_info[0].u.rbuf); HDassert(io_info->dset); HDassert(io_info->dset->shared); HDassert(io_info->dset->shared->extfile_prefix); @@ -485,9 +485,9 @@ H5D__efl_readvv(const H5D_io_info_t *io_info, HDassert(mem_off_arr); /* Set up user data for H5VM_opvv() */ - udata.efl = &(io_info->store->efl); + udata.efl = &(io_info->dsets_info[0].store->efl); udata.dset = io_info->dset; - udata.rbuf = (unsigned char *)io_info->u.rbuf; + udata.rbuf = (unsigned char *)io_info->dsets_info[0].u.rbuf; /* Call generic sequence operation routine */ if((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, @@ -556,8 +556,8 @@ H5D__efl_writevv(const H5D_io_info_t *io_info, /* Check args */ HDassert(io_info); - HDassert(io_info->store->efl.nused > 0); - HDassert(io_info->u.wbuf); + HDassert(io_info->dsets_info[0].store->efl.nused > 0); + HDassert(io_info->dsets_info[0].u.wbuf); HDassert(io_info->dset); HDassert(io_info->dset->shared); HDassert(io_info->dset->shared->extfile_prefix); @@ -569,9 +569,9 @@ H5D__efl_writevv(const H5D_io_info_t *io_info, HDassert(mem_off_arr); /* Set up user data for H5VM_opvv() */ - udata.efl = &(io_info->store->efl); + udata.efl = &(io_info->dsets_info[0].store->efl); udata.dset = io_info->dset; - udata.wbuf = (const unsigned char *)io_info->u.wbuf; + udata.wbuf = (const unsigned char *)io_info->dsets_info[0].u.wbuf; /* Call generic sequence operation routine */ if((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, diff --git a/src/H5Dint.c b/src/H5Dint.c index bdedd1e..682c16c 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -501,7 +501,7 @@ done: /*------------------------------------------------------------------------- * Function: H5D__get_space_status * - * Purpose: Returns the status of data space allocation. + * Purpose: Returns the status of dataspace allocation. * * Return: * Success: Non-negative @@ -1811,9 +1811,17 @@ H5D_close(H5D_t *dataset) /* Free cached information for each kind of dataset */ switch(dataset->shared->layout.type) { case H5D_CONTIGUOUS: + /* Check for skip list for iterating over pieces during I/O to close */ + if(dataset->shared->cache.sel_pieces) { + HDassert(H5SL_count(dataset->shared->cache.sel_pieces) == 0); + H5SL_close(dataset->shared->cache.sel_pieces); + dataset->shared->cache.sel_pieces = NULL; + } /* end if */ + /* Free the data sieve buffer, if it's been allocated */ if(dataset->shared->cache.contig.sieve_buf) dataset->shared->cache.contig.sieve_buf = (unsigned char *)H5FL_BLK_FREE(sieve_buf,dataset->shared->cache.contig.sieve_buf); + break; case H5D_CHUNKED: @@ -1824,6 +1832,13 @@ H5D_close(H5D_t *dataset) dataset->shared->cache.chunk.sel_chunks = NULL; } /* end if */ + /* Check for skip list for iterating over pieces during I/O to close */ + if(dataset->shared->cache.sel_pieces) { + HDassert(H5SL_count(dataset->shared->cache.sel_pieces) == 0); + H5SL_close(dataset->shared->cache.sel_pieces); + dataset->shared->cache.sel_pieces = NULL; + } /* end if */ + /* Check for cached single chunk dataspace */ if(dataset->shared->cache.chunk.single_space) { (void)H5S_close(dataset->shared->cache.chunk.single_space); @@ -1831,10 +1846,9 @@ H5D_close(H5D_t *dataset) } /* end if */ /* Check for cached single element chunk info */ - if(dataset->shared->cache.chunk.single_chunk_info) { - dataset->shared->cache.chunk.single_chunk_info = H5FL_FREE(H5D_chunk_info_t, dataset->shared->cache.chunk.single_chunk_info); - dataset->shared->cache.chunk.single_chunk_info = NULL; - } /* end if */ + if(dataset->shared->cache.chunk.single_chunk_info) + dataset->shared->cache.chunk.single_chunk_info = + H5FL_FREE(H5D_chunk_info_t, dataset->shared->cache.chunk.single_chunk_info); break; case H5D_COMPACT: @@ -2643,6 +2657,7 @@ herr_t H5D__vlen_get_buf_size(void H5_ATTR_UNUSED *elem, hid_t type_id, unsigned H5_ATTR_UNUSED ndim, const hsize_t *point, void *op_data) { H5D_vlen_bufsize_t *vlen_bufsize = (H5D_vlen_bufsize_t *)op_data; + H5D_dset_info_t *dset_info = NULL; /* Internal multi-dataset info placeholder */ H5T_t *dt; /* Datatype for operation */ herr_t ret_value = SUCCEED; /* Return value */ @@ -2663,11 +2678,30 @@ H5D__vlen_get_buf_size(void H5_ATTR_UNUSED *elem, hid_t type_id, unsigned H5_ATT if(H5S_select_elements(vlen_bufsize->fspace, H5S_SELECT_SET, (size_t)1, point) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't select point") - /* Read in the point (with the custom VL memory allocator) */ - if(H5D__read(vlen_bufsize->dset, type_id, vlen_bufsize->mspace, vlen_bufsize->fspace, vlen_bufsize->xfer_pid, vlen_bufsize->fl_tbuf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read point") + { + hid_t file_id; /* File ID for operation */ + + /* Alloc dset_info */ + if(NULL == (dset_info = (H5D_dset_info_t *)H5MM_calloc(sizeof(H5D_dset_info_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset info array buffer") + + dset_info->dset = vlen_bufsize->dset; + dset_info->mem_space = vlen_bufsize->mspace; + dset_info->file_space = vlen_bufsize->fspace; + dset_info->u.rbuf = vlen_bufsize->fl_tbuf; + dset_info->mem_type_id = type_id; + + /* Retrieve file_id */ + file_id = H5F_FILE_ID(dset_info->dset->oloc.file); + + /* Read in the point (with the custom VL memory allocator) */ + if(H5D__read(file_id, vlen_bufsize->xfer_pid, 1, dset_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") + } done: + if(dset_info) + H5MM_xfree(dset_info); FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__vlen_get_buf_size() */ diff --git a/src/H5Dio.c b/src/H5Dio.c index 104a632..26e02c5 100644 --- a/src/H5Dio.c +++ b/src/H5Dio.c @@ -49,25 +49,27 @@ /* Local Prototypes */ /********************/ -/* Internal I/O routines */ -static herr_t H5D__pre_write(H5D_t *dset, hbool_t direct_write, hid_t mem_type_id, - const H5S_t *mem_space, const H5S_t *file_space, hid_t dxpl_id, const void *buf); +/* Internal I/O routines for single-dset */ +static herr_t H5D__pre_read(hid_t file_id, hid_t dxpl_id, size_t count, + H5D_dset_info_t *dset_info); +static herr_t H5D__pre_write(hid_t file_id, hid_t dxpl_id, size_t count, + H5D_dset_info_t *dset_info); + +/* Internal I/O routines for multi-dset */ + /* Setup/teardown routines */ static herr_t H5D__ioinfo_init(H5D_t *dset, #ifndef H5_HAVE_PARALLEL -const + const #endif /* H5_HAVE_PARALLEL */ - H5D_dxpl_cache_t *dxpl_cache, - hid_t dxpl_id, const H5D_type_info_t *type_info, H5D_storage_t *store, - H5D_io_info_t *io_info); + H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, H5D_dset_info_t *dset_info, + H5D_storage_t *store, H5D_io_info_t *io_info); static herr_t H5D__typeinfo_init(const H5D_t *dset, const H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, hid_t mem_type_id, hbool_t do_write, H5D_type_info_t *type_info); #ifdef H5_HAVE_PARALLEL -static herr_t H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, - hid_t dxpl_id, const H5S_t *file_space, const H5S_t *mem_space, - const H5D_type_info_t *type_info, const H5D_chunk_map_t *fm); +static herr_t H5D__ioinfo_adjust(const size_t count, H5D_io_info_t *io_info, hid_t dxpl_id); static herr_t H5D__ioinfo_term(H5D_io_info_t *io_info); #endif /* H5_HAVE_PARALLEL */ static herr_t H5D__typeinfo_term(const H5D_type_info_t *type_info); @@ -86,8 +88,96 @@ static herr_t H5D__typeinfo_term(const H5D_type_info_t *type_info); H5FL_BLK_DEFINE(type_conv); /* Declare a free list to manage the H5D_chunk_map_t struct */ -H5FL_DEFINE(H5D_chunk_map_t); +/* H5FL_DEFINE(H5D_chunk_map_t); */ + + +/*------------------------------------------------------------------------- + * Function: H5D__init_dset_info + * + * Purpose: Initializes a H5D_dset_info_t from a set of user parameters, + * while checking parameters too. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Friday, August 29, 2014 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__init_dset_info(H5D_dset_info_t *dset_info, hid_t dset_id, + hid_t mem_type_id, hid_t mem_space_id, hid_t dset_space_id, + const H5D_dset_buf_t *u_buf) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Get dataset */ + if(NULL == (dset_info->dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") + if(NULL == dset_info->dset->oloc.file) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") + /* Check for invalid space IDs */ + if(mem_space_id < 0 || dset_space_id < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + + /* Get file dataspace */ + if(H5S_ALL != dset_space_id) { + if(NULL == (dset_info->file_space = (const H5S_t *)H5I_object_verify(dset_space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + + /* Check for valid selection */ + if(H5S_SELECT_VALID(dset_info->file_space) != TRUE) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "file selection+offset not within extent") + } /* end if */ + else + dset_info->file_space = dset_info->dset->shared->space; + + /* Get memory dataspace */ + if(H5S_ALL != mem_space_id) { + if(NULL == (dset_info->mem_space = (const H5S_t *)H5I_object_verify(mem_space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + + /* Check for valid selection */ + if(H5S_SELECT_VALID(dset_info->mem_space) != TRUE) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "memory selection+offset not within extent") + } /* end if */ + else + dset_info->mem_space = dset_info->file_space; + + /* Get memory datatype */ + dset_info->mem_type_id = mem_type_id; + + /* Get buffer */ + dset_info->u = *u_buf; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__init_dset_info() */ + +static hid_t +H5D__verify_location(size_t count, const H5D_dset_info_t *info) +{ + hid_t file_id; + size_t u; + hid_t ret_value = FAIL; /* Return value */ + + FUNC_ENTER_STATIC + + file_id = H5F_FILE_ID(info[0].dset->oloc.file); + + for(u = 1; u < count; u++) { + if(file_id != H5F_FILE_ID(info[u].dset->oloc.file)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dataset's file ID doesn't match file_id parameter") + } /* end for */ + + ret_value = file_id; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__verify_location */ /*------------------------------------------------------------------------- @@ -122,107 +212,241 @@ H5FL_DEFINE(H5D_chunk_map_t); */ herr_t H5Dread(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, - hid_t file_space_id, hid_t plist_id, void *buf/*out*/) + hid_t file_space_id, hid_t dxpl_id, void *buf/*out*/) { - H5D_t *dset = NULL; - const H5S_t *mem_space = NULL; - const H5S_t *file_space = NULL; - H5P_genplist_t *plist; /* Property list pointer */ - hsize_t *direct_offset = NULL; - hbool_t direct_read = FALSE; - uint32_t direct_filters = 0; - herr_t ret_value = SUCCEED; /* Return value */ + H5D_dset_info_t *dset_info = NULL; /* Internal multi-dataset info placeholder */ + H5D_dset_buf_t u_buf; /* Buffer pointer */ + hid_t file_id; /* File ID for operation */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE6("e", "iiiiix", dset_id, mem_type_id, mem_space_id, file_space_id, - plist_id, buf); + dxpl_id, buf); - /* check arguments */ - if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") - if(NULL == dset->oloc.file) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") + /* Get the default dataset transfer property list if the user didn't provide one */ + if(H5P_DEFAULT == dxpl_id) + dxpl_id = H5P_DATASET_XFER_DEFAULT; + else + if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms") - if(mem_space_id < 0 || file_space_id < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") + /* Alloc dset_info */ + if(NULL == (dset_info = (H5D_dset_info_t *)H5MM_calloc(sizeof(H5D_dset_info_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset info array buffer") - if(H5S_ALL != mem_space_id) { - if(NULL == (mem_space = (const H5S_t *)H5I_object_verify(mem_space_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") + /* Translate public multi-dataset info to internal structure */ + /* (And check parameters) */ + u_buf.rbuf = buf; + if(H5D__init_dset_info(dset_info, dset_id, mem_type_id, mem_space_id, file_space_id, &u_buf) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't init dataset info") - /* Check for valid selection */ - if(H5S_SELECT_VALID(mem_space) != TRUE) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "selection+offset not within extent") - } /* end if */ + /* Retrieve file_id */ + file_id = H5F_FILE_ID(dset_info->dset->oloc.file); - if(H5S_ALL != file_space_id) { - if(NULL == (file_space = (const H5S_t *)H5I_object_verify(file_space_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") + /* Call common pre-read routine */ + if(H5D__pre_read(file_id, dxpl_id, 1, dset_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't prepare for reading data") - /* Check for valid selection */ - if(H5S_SELECT_VALID(file_space) != TRUE) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "selection+offset not within extent") - } /* end if */ +done: + if(dset_info) + H5MM_xfree(dset_info); + + FUNC_LEAVE_API(ret_value) +} /* end H5Dread() */ + + +/*------------------------------------------------------------------------- + * Function: H5Dread_multi + * + * Purpose: Multi-version of H5Dread(), which reads selections from + * multiple datasets from a file into application memory BUFS. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jonathan Kim Nov, 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Dread_multi(hid_t dxpl_id, size_t count, H5D_rw_multi_t *info) +{ + H5D_dset_info_t *dset_info = NULL; /* Pointer to internal list of multi-dataset info */ + size_t u; /* Local index variable */ + hid_t file_id; /* file ID where datasets are located */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE3("e", "iz*Dm", dxpl_id, count, info); + + if(count <= 0) + HGOTO_DONE(SUCCEED) /* Get the default dataset transfer property list if the user didn't provide one */ - if (H5P_DEFAULT == plist_id) - plist_id= H5P_DATASET_XFER_DEFAULT; + if(H5P_DEFAULT == dxpl_id) + dxpl_id = H5P_DATASET_XFER_DEFAULT; else - if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_XFER)) + if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER)) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms") + /* Alloc dset_info */ + if(NULL == (dset_info = (H5D_dset_info_t *)H5MM_calloc(count * sizeof(H5D_dset_info_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset info array buffer") + + /* Translate public multi-dataset info to internal structure */ + /* (And check parameters) */ + for(u = 0; u < count; u++) { + if(H5D__init_dset_info(&dset_info[u], info[u].dset_id, info[u].mem_type_id, info[u].mem_space_id, + info[u].dset_space_id, &(info[u].u.rbuf)) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't init dataset info") + } /* end for */ + + if((file_id = H5D__verify_location(count, dset_info)) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "datasets are not in the same file") + + /* Call common pre-read routine */ + if(H5D__pre_read(file_id, dxpl_id, count, dset_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't prepare for reading data") + +done: + if(dset_info) + H5MM_xfree(dset_info); + + FUNC_LEAVE_API(ret_value) +} /* end H5Dread_multi() */ + + +/*------------------------------------------------------------------------- + * Function: H5D__pre_read + * + * Purpose: Sets up a read operation. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner Apr, 2014 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__pre_read(hid_t file_id, hid_t dxpl_id, size_t count, + H5D_dset_info_t *dset_info) +{ + H5FD_mpio_xfer_t xfer_mode; /* Parallel I/O transfer mode */ + hbool_t broke_mdset = FALSE; /* Whether to break multi-dataset option */ + size_t u; /* Local index variable */ + H5P_genplist_t *plist; /* Property list pointer */ + H5P_genplist_t *plist_chunk; /* Property list pointer */ + hsize_t *direct_offset = NULL; + hbool_t direct_read = FALSE; + uint32_t direct_filters = 0; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* check args */ + HDassert(dxpl_id > 0); + HDassert(count > 0); + HDassert(dset_info); + + /* Retrieve DXPL for queries below */ + if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER))) + HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dxpl") + + /* Get the transfer mode */ + if(H5P_get(plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to get value") + /* Get the dataset transfer property list */ - if(NULL == (plist = (H5P_genplist_t *)H5I_object(plist_id))) + if(NULL == (plist_chunk = (H5P_genplist_t *)H5I_object(dxpl_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") /* Retrieve the 'direct read' flag */ - if(H5P_get(plist, H5D_XFER_DIRECT_CHUNK_READ_FLAG_NAME, &direct_read) < 0) + if(H5P_get(plist_chunk, H5D_XFER_DIRECT_CHUNK_READ_FLAG_NAME, &direct_read) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting flag for direct chunk read") if(direct_read) { - unsigned u; hsize_t internal_offset[H5O_LAYOUT_NDIMS]; - if(H5D_CHUNKED != dset->shared->layout.type) + if(H5D_CHUNKED != dset_info[0].dset->shared->layout.type) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a chunked dataset") /* Get the direct chunk offset property */ - if(H5P_get(plist, H5D_XFER_DIRECT_CHUNK_READ_OFFSET_NAME, &direct_offset) < 0) + if(H5P_get(plist_chunk, H5D_XFER_DIRECT_CHUNK_READ_OFFSET_NAME, &direct_offset) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting direct offset from xfer properties") /* The library's chunking code requires the offset terminates with a zero. So transfer the * offset array to an internal offset array */ - for(u = 0; u < dset->shared->ndims; u++) { + for(u = 0; u < dset_info[0].dset->shared->ndims; u++) { /* Make sure the offset doesn't exceed the dataset's dimensions */ - if(direct_offset[u] > dset->shared->curr_dims[u]) + if(direct_offset[u] > dset_info[0].dset->shared->curr_dims[u]) HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "offset exceeds dimensions of dataset") /* Make sure the offset fall right on a chunk's boundary */ - if(direct_offset[u] % dset->shared->layout.u.chunk.dim[u]) + if(direct_offset[u] % dset_info[0].dset->shared->layout.u.chunk.dim[u]) HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "offset doesn't fall on chunks's boundary") internal_offset[u] = direct_offset[u]; } /* end for */ /* Terminate the offset with a zero */ - internal_offset[dset->shared->ndims] = 0; - + internal_offset[dset_info[0].dset->shared->ndims] = 0; /* Read the raw chunk */ - if(H5D__chunk_direct_read(dset, plist_id, internal_offset, &direct_filters, buf) < 0) + if(H5D__chunk_direct_read(dset_info[0].dset, dxpl_id, internal_offset, &direct_filters, dset_info[0].u.rbuf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read chunk directly") /* Set the chunk filter mask property */ - if(H5P_set(plist, H5D_XFER_DIRECT_CHUNK_READ_FILTERS_NAME, &direct_filters) < 0) + if(H5P_set(plist_chunk, H5D_XFER_DIRECT_CHUNK_READ_FILTERS_NAME, &direct_filters) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error setting filter mask xfer property") } else { - /* read raw data */ - if(H5D__read(dset, mem_type_id, mem_space, file_space, plist_id, buf/*out*/) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") + + /* In independent mode or with an unsupported layout, for now just + read each dataset individually */ + if(xfer_mode == H5FD_MPIO_INDEPENDENT) + broke_mdset = TRUE; + else { + /* Multi-dset I/O currently supports CHUNKED and internal CONTIGUOUS + * only, not external CONTIGUOUS (EFL) or COMPACT. Fall back to + * individual dataset reads if any dataset uses an unsupported layout. + */ + for(u = 0; u < count; u++) { + if(!(dset_info[u].dset->shared->layout.type == H5D_CHUNKED || + (dset_info[u].dset->shared->layout.type == H5D_CONTIGUOUS && + dset_info[u].dset->shared->layout.ops != H5D_LOPS_EFL))) { + broke_mdset = TRUE; + break; + } + } /* end for */ + } + + if(broke_mdset) { + /* Read raw data from each dataset by iteself */ + for(u = 0; u < count; u++) + if(H5D__read(file_id, dxpl_id, 1, &dset_info[u]) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") + } /* end if */ + else { + HDassert(xfer_mode == H5FD_MPIO_COLLECTIVE); + + if(count > 0) { + if(H5D__read(file_id, dxpl_id, count, dset_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") + } /* end if */ +#ifdef H5_HAVE_PARALLEL + /* MSC - I do not think we should allow for this. I think we + should make the multi dataset APIs enforce a uniform list + of datasets among all processes, and users would enter a + NULL selection when a process does not have anything to + write to a particulat dataset. */ + else { + if(H5D__match_coll_calls(file_id, plist, TRUE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "failed in matching collective MPI calls") + } /* end else */ +#endif /* H5_HAVE_PARALLEL */ + } /* end else */ } done: - FUNC_LEAVE_API(ret_value) -} /* end H5Dread() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__pre_read() */ /*------------------------------------------------------------------------- @@ -260,23 +484,15 @@ herr_t H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, hid_t dxpl_id, const void *buf) { - H5D_t *dset = NULL; - H5P_genplist_t *plist; /* Property list pointer */ - const H5S_t *mem_space = NULL; - const H5S_t *file_space = NULL; - hbool_t direct_write = FALSE; - herr_t ret_value = SUCCEED; /* Return value */ + H5D_dset_info_t *dset_info = NULL; /* Internal multi-dataset info placeholder */ + H5D_dset_buf_t u_buf; /* Buffer pointer */ + hid_t file_id; /* File ID for operation */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE6("e", "iiiii*x", dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf); - /* check arguments */ - if(NULL == (dset = (H5D_t *)H5I_object_verify(dset_id, H5I_DATASET))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") - if(NULL == dset->oloc.file) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") - /* Get the default dataset transfer property list if the user didn't provide one */ if(H5P_DEFAULT == dxpl_id) dxpl_id= H5P_DATASET_XFER_DEFAULT; @@ -284,43 +500,88 @@ H5Dwrite(hid_t dset_id, hid_t mem_type_id, hid_t mem_space_id, if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER)) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms") - /* Get the dataset transfer property list */ - if(NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") + /* Alloc dset_info */ + if(NULL == (dset_info = (H5D_dset_info_t *)H5MM_calloc(sizeof(H5D_dset_info_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset info array buffer") - /* Retrieve the 'direct write' flag */ - if(H5P_get(plist, H5D_XFER_DIRECT_CHUNK_WRITE_FLAG_NAME, &direct_write) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting flag for direct chunk write") + /* Translate public multi-dataset info to internal structure */ + /* (And check parameters) */ + u_buf.wbuf = buf; + if(H5D__init_dset_info(dset_info, dset_id, mem_type_id, mem_space_id, file_space_id, &u_buf) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't init dataset info") - /* Check dataspace selections if this is not a direct write */ - if(!direct_write) { - if(mem_space_id < 0 || file_space_id < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + /* Retrieve file_id */ + file_id = H5F_FILE_ID(dset_info->dset->oloc.file); - if(H5S_ALL != mem_space_id) { - if(NULL == (mem_space = (const H5S_t *)H5I_object_verify(mem_space_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + /* Call common pre-write routine */ + if(H5D__pre_write(file_id, dxpl_id, 1, dset_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't prepare for writing data") - /* Check for valid selection */ - if(H5S_SELECT_VALID(mem_space) != TRUE) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "memory selection+offset not within extent") - } /* end if */ - if(H5S_ALL != file_space_id) { - if(NULL == (file_space = (const H5S_t *)H5I_object_verify(file_space_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") +done: + if(dset_info) + H5MM_xfree(dset_info); + FUNC_LEAVE_API(ret_value) +} /* end H5Dwrite() */ - /* Check for valid selection */ - if(H5S_SELECT_VALID(file_space) != TRUE) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "file selection+offset not within extent") - } /* end if */ + +/*------------------------------------------------------------------------- + * Function: H5Dwrite_multi + * + * Purpose: Multi-version of H5Dwrite(), which writes selections from + * application memory BUFs into multiple datasets in a file. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Jonathan Kim Nov, 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Dwrite_multi(hid_t dxpl_id, size_t count, const H5D_rw_multi_t *info) +{ + H5D_dset_info_t *dset_info = NULL; /* Pointer to internal list of multi-dataset info */ + size_t u; /* Local index variable */ + hid_t file_id; /* file ID where datasets are located */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE3("e", "iz*Dm", dxpl_id, count, info); + + if(count <= 0) + HGOTO_DONE(SUCCEED) + + /* Get the default dataset transfer property list if the user didn't provide one */ + if(H5P_DEFAULT == dxpl_id) + dxpl_id = H5P_DATASET_XFER_DEFAULT; + else + if(TRUE != H5P_isa_class(dxpl_id, H5P_DATASET_XFER)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not xfer parms") + + /* Alloc dset_info */ + if(NULL == (dset_info = (H5D_dset_info_t *)H5MM_calloc(count * sizeof(H5D_dset_info_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset info array buffer") + + /* Translate public multi-dataset info to internal structure */ + /* (And check parameters) */ + for(u = 0; u < count; u++) { + if(H5D__init_dset_info(&dset_info[u], info[u].dset_id, info[u].mem_type_id, info[u].mem_space_id, + info[u].dset_space_id, &(info[u].u.wbuf)) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't init dataset info") } - if(H5D__pre_write(dset, direct_write, mem_type_id, mem_space, file_space, dxpl_id, buf) < 0) + if((file_id = H5D__verify_location(count, dset_info)) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "datasets are not in the same file") + + /* Call common pre-write routine */ + if(H5D__pre_write(file_id, dxpl_id, count, dset_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't prepare for writing data") done: + if(dset_info) + H5MM_xfree(dset_info); + FUNC_LEAVE_API(ret_value) -} /* end H5Dwrite() */ +} /* end H5Dwrite_multi() */ /*------------------------------------------------------------------------- @@ -330,34 +591,49 @@ done: * * Return: Non-negative on success/Negative on failure * - * Programmer: Raymond Lu - * 2 November 2012 + * Programmer: Jonathan Kim Nov, 2013 * *------------------------------------------------------------------------- */ static herr_t -H5D__pre_write(H5D_t *dset, hbool_t direct_write, hid_t mem_type_id, - const H5S_t *mem_space, const H5S_t *file_space, - hid_t dxpl_id, const void *buf) +H5D__pre_write(hid_t file_id, hid_t dxpl_id, size_t count, + H5D_dset_info_t *dset_info) { - herr_t ret_value = SUCCEED; /* Return value */ + H5P_genplist_t *plist; /* DXPL property list pointer */ + hbool_t direct_write = FALSE; /* Flag for direct writing */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC - /* Direct chunk write */ - if(direct_write) { - H5P_genplist_t *plist; /* Property list pointer */ - uint32_t direct_filters; - hsize_t *direct_offset; - uint32_t direct_datasize; - hsize_t internal_offset[H5O_LAYOUT_NDIMS]; - unsigned u; /* Local index variable */ + /* check args */ + HDassert(dxpl_id > 0); + HDassert(count > 0); + HDassert(dset_info); + + /* Retrieve DXPL for queries below */ + if(NULL == (plist = H5P_object_verify(dxpl_id, H5P_DATASET_XFER))) + HGOTO_ERROR(H5E_PLIST, H5E_BADTYPE, FAIL, "not a dxpl") - /* Get the dataset transfer property list */ - if(NULL == (plist = (H5P_genplist_t *)H5I_object(dxpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") + /* Check if direct write or not */ + if(H5P_get(plist, H5D_XFER_DIRECT_CHUNK_WRITE_FLAG_NAME, &direct_write) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting flag for direct chunk write") - if(H5D_CHUNKED != dset->shared->layout.type) + /* Direct chunk write */ + if(direct_write) { + uint32_t direct_filters; /* Filters already applied to chunk */ + hsize_t *direct_offset; /* Offset of chunk */ + uint32_t direct_datasize; /* [Pre-compressed] size of chunk */ + int sndims; /* Dataspace rank (signed) */ + unsigned ndims; /* Dataspace rank */ + hsize_t dims[H5O_LAYOUT_NDIMS]; /* Dataspace dimensions */ + hsize_t internal_offset[H5O_LAYOUT_NDIMS]; /* Internal copy of the chunk offset */ + unsigned u; /* Local index variable */ + + /* Sanity check */ + HDassert(count == 1); + + /* Verify dataset is chunked */ + if(H5D_CHUNKED != dset_info[0].dset->shared->layout.type) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a chunked dataset") /* Retrieve parameters for direct chunk write */ @@ -368,31 +644,87 @@ H5D__pre_write(H5D_t *dset, hbool_t direct_write, hid_t mem_type_id, if(H5P_get(plist, H5D_XFER_DIRECT_CHUNK_WRITE_DATASIZE_NAME, &direct_datasize) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "error getting data size for direct chunk write") - /* The library's chunking code requires the offset terminates with a zero. So transfer the - * offset array to an internal offset array */ - for(u = 0; u < dset->shared->ndims; u++) { + /* The library's chunking code requires the offset terminates with a + * zero. So transfer the offset array to an internal offset array */ + if((sndims = H5S_get_simple_extent_dims(dset_info[0].dset->shared->space, dims, NULL)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve dataspace extent dims") + H5_CHECKED_ASSIGN(ndims, unsigned, sndims, int); + + /* Sanity check chunk offset and set up internal offset array */ + for(u = 0; u < ndims; u++) { /* Make sure the offset doesn't exceed the dataset's dimensions */ - if(direct_offset[u] > dset->shared->curr_dims[u]) + if(direct_offset[u] > dset_info[0].dset->shared->curr_dims[u]) HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "offset exceeds dimensions of dataset") /* Make sure the offset fall right on a chunk's boundary */ - if(direct_offset[u] % dset->shared->layout.u.chunk.dim[u]) + if(direct_offset[u] % dset_info[0].dset->shared->layout.u.chunk.dim[u]) HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "offset doesn't fall on chunks's boundary") internal_offset[u] = direct_offset[u]; } /* end for */ - - /* Terminate the offset with a zero */ - internal_offset[dset->shared->ndims] = 0; - /* write raw data */ - if(H5D__chunk_direct_write(dset, dxpl_id, direct_filters, internal_offset, direct_datasize, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write chunk directly") - } /* end if */ - else { /* Normal write */ + /* Terminate the offset with a zero */ + internal_offset[ndims] = 0; + /* write raw data */ - if(H5D__write(dset, mem_type_id, mem_space, file_space, dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") + if(H5D__chunk_direct_write(dset_info[0].dset, dxpl_id, direct_filters, internal_offset, + direct_datasize, dset_info[0].u.wbuf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write chunk directly") + } /* end if */ + else { + size_t u; /* Local index variable */ + hbool_t broke_mdset = FALSE; /* Whether to break multi-dataset option */ + H5FD_mpio_xfer_t xfer_mode; /* Parallel I/O transfer mode */ + + /* Get the transfer mode */ + if(H5P_get(plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to get value") + + /* In independent mode or with an unsupported layout, for now + just write each dataset individually */ + if(xfer_mode == H5FD_MPIO_INDEPENDENT) + broke_mdset = TRUE; + else { + /* Multi-dset I/O currently supports CHUNKED and internal CONTIGUOUS + * only, not external CONTIGUOUS (EFL) or COMPACT. Fall back to + * individual dataset writes if any dataset uses an unsupported layout. + */ + for(u = 0; u < count; u++) { + if(!(dset_info[u].dset->shared->layout.type == H5D_CHUNKED || + (dset_info[u].dset->shared->layout.type == H5D_CONTIGUOUS && + dset_info[u].dset->shared->layout.ops != H5D_LOPS_EFL))) { + broke_mdset = TRUE; + break; + } + } /* end for */ + } + + if(broke_mdset) { + /* Write raw data to each dataset by iteself */ + for(u = 0; u < count; u++) + if(H5D__write(file_id, dxpl_id, 1, &dset_info[u]) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") + } /* end if */ + else { + HDassert(xfer_mode == H5FD_MPIO_COLLECTIVE); + + if(count > 0) { + if(H5D__write(file_id, dxpl_id, count, dset_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") + } /* end if */ + +#ifdef H5_HAVE_PARALLEL + /* MSC - I do not think we should allow for this. I think we + should make the multi dataset APIs enforce a uniform list + of datasets among all processes, and users would enter a + NULL selection when a process does not have anything to + write to a particulat dataset. */ + else { + if(H5D__match_coll_calls(file_id, plist, FALSE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "failed in matching collective MPI calls") + } /* end else */ +#endif /* H5_HAVE_PARALLEL */ + } /* end else */ } /* end else */ done: @@ -403,25 +735,22 @@ done: /*------------------------------------------------------------------------- * Function: H5D__read * - * Purpose: Reads (part of) a DATASET into application memory BUF. See - * H5Dread() for complete details. + * Purpose: Reads multiple (part of) DATASETs into application memory BUFs. + * See H5Dread_multi() for complete details. * * Return: Non-negative on success/Negative on failure * - * Programmer: Robb Matzke - * Thursday, December 4, 1997 + * Programmer: Jonathan Kim Nov, 2013 * *------------------------------------------------------------------------- */ herr_t -H5D__read(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, - const H5S_t *file_space, hid_t dxpl_id, void *buf/*out*/) +H5D__read(hid_t file_id, hid_t dxpl_id, size_t count, + H5D_dset_info_t *dset_info) { - H5D_chunk_map_t *fm = NULL; /* Chunk file<->memory mapping */ - H5D_io_info_t io_info; /* Dataset I/O info */ - H5D_type_info_t type_info; /* Datatype info for operation */ - hbool_t type_info_init = FALSE; /* Whether the datatype info has been initialized */ - H5S_t * projected_mem_space = NULL; /* If not NULL, ptr to dataspace containing a */ + H5D_io_info_t io_info; /* Dataset I/O info for multi dsets */ + size_t type_info_init = 0; /* Number of datatype info structs that have been initialized */ + H5S_t ** projected_mem_space; /* If not NULL, ptr to dataspace containing a */ /* projection of the supplied mem_space to a new */ /* data space with rank equal to that of */ /* file_space. */ @@ -434,171 +763,236 @@ H5D__read(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, /* Note that if this variable is used, the */ /* projected mem space must be discarded at the */ /* end of the function to avoid a memory leak. */ - H5D_storage_t store; /*union of EFL and chunk pointer in file space */ - hssize_t snelmts; /*total number of elmts (signed) */ - hsize_t nelmts; /*total number of elmts */ + H5D_storage_t *store = NULL; /* Union of EFL and chunk pointer in file space */ + hssize_t snelmts; /* Total number of elmts (signed) */ + hsize_t nelmts; /* Total number of elmts */ hbool_t io_info_init = FALSE; /* Whether the I/O info has been initialized */ - hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */ + size_t io_op_init = 0; /* Number I/O ops that have been initialized */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ + size_t i; /* Local index variable */ char fake_char; /* Temporary variable for NULL buffer pointers */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_PACKAGE_TAG(dxpl_id, dataset->oloc.addr, FAIL) + FUNC_ENTER_NOAPI(FAIL) - /* check args */ - HDassert(dataset && dataset->oloc.file); + /* init io_info */ + io_info.sel_pieces = NULL; + io_info.store_faddr = 0; + io_info.base_maddr_r = NULL; - if(!file_space) - file_space = dataset->shared->space; - if(!mem_space) - mem_space = file_space; - if((snelmts = H5S_GET_SELECT_NPOINTS(mem_space)) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dst dataspace has invalid selection") - H5_CHECKED_ASSIGN(nelmts, hsize_t, snelmts, hssize_t); + /* Create global piece skiplist */ + if(NULL == (io_info.sel_pieces = H5SL_create(H5SL_TYPE_HADDR, NULL))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for piece selections") - /* Fill the DXPL cache values for later use */ - if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") + /* Use provided dset_info */ + io_info.dsets_info = dset_info; - /* Set up datatype info for operation */ - if(H5D__typeinfo_init(dataset, dxpl_cache, dxpl_id, mem_type_id, FALSE, &type_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info") - type_info_init = TRUE; + /* Allocate other buffers */ + if(NULL == (projected_mem_space = (H5S_t **)H5MM_calloc(count * sizeof(H5S_t*)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "couldn't allocate dset space array ptr") + if(NULL == (store = (H5D_storage_t *)H5MM_malloc(count * sizeof(H5D_storage_t)))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTALLOC, FAIL, "couldn't allocate dset storage info array buffer") -#ifdef H5_HAVE_PARALLEL - /* Collective access is not permissible without a MPI based VFD */ - if(dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE && - !(H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_HAS_MPI))) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based drivers only") -#endif /*H5_HAVE_PARALLEL*/ + /* init both dxpls to the original one */ + io_info.md_dxpl_id = dxpl_id; + io_info.raw_dxpl_id = dxpl_id; - /* Make certain that the number of elements in each selection is the same */ - if(nelmts != (hsize_t)H5S_GET_SELECT_NPOINTS(file_space)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src and dest data spaces have different sizes") + /* set the dxpl IO type for sanity checking at the FD layer */ +#ifdef H5_DEBUG_BUILD + if(H5D_set_io_info_dxpls(&io_info, dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't set metadata and raw data dxpls") +#endif /* H5_DEBUG_BUILD */ - /* Check for a NULL buffer, after the H5S_ALL dataspace selection has been handled */ - if(NULL == buf) { - /* Check for any elements selected (which is invalid) */ - if(nelmts > 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer") + /* iterate over all dsets and construct I/O information necessary to do I/O */ + for(i = 0; i < count; i++) { + /* check args */ + if(NULL == dset_info[i].dset) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") + if(NULL == dset_info[i].dset->oloc.file) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") - /* If the buffer is nil, and 0 element is selected, make a fake buffer. - * This is for some MPI package like ChaMPIon on NCSA's tungsten which - * doesn't support this feature. - */ - buf = &fake_char; - } /* end if */ + /* Fill the DXPL cache values for later use */ + if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") - /* Make sure that both selections have their extents set */ - if(!(H5S_has_extent(file_space))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set") - if(!(H5S_has_extent(mem_space))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set") - - /* H5S_select_shape_same() has been modified to accept topologically identical - * selections with different rank as having the same shape (if the most - * rapidly changing coordinates match up), but the I/O code still has - * difficulties with the notion. - * - * To solve this, we check to see if H5S_select_shape_same() returns true, - * and if the ranks of the mem and file spaces are different. If the are, - * construct a new mem space that is equivalent to the old mem space, and - * use that instead. - * - * Note that in general, this requires us to touch up the memory buffer as - * well. - */ - if(TRUE == H5S_select_shape_same(mem_space, file_space) && - H5S_GET_EXTENT_NDIMS(mem_space) != H5S_GET_EXTENT_NDIMS(file_space)) { - void *adj_buf = NULL; /* Pointer to the location in buf corresponding */ - /* to the beginning of the projected mem space. */ - - /* Attempt to construct projected dataspace for memory dataspace */ - if(H5S_select_construct_projection(mem_space, &projected_mem_space, - (unsigned)H5S_GET_EXTENT_NDIMS(file_space), buf, (const void **)&adj_buf, type_info.dst_type_size) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace") - HDassert(projected_mem_space); - HDassert(adj_buf); - - /* Switch to using projected memory dataspace & adjusted buffer */ - mem_space = projected_mem_space; - buf = adj_buf; - } /* end if */ + /* Set up datatype info for operation */ + if(H5D__typeinfo_init(dset_info[i].dset, dxpl_cache, dxpl_id, dset_info[i].mem_type_id, + FALSE, &(dset_info[i].type_info)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info") + type_info_init++; +#ifdef H5_HAVE_PARALLEL + /* Collective access is not permissible without a MPI based VFD */ + if(dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE && + !(H5F_HAS_FEATURE(dset_info[i].dset->oloc.file, H5FD_FEAT_HAS_MPI))) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based drivers only") +#endif /*H5_HAVE_PARALLEL*/ - /* Retrieve dataset properties */ - /* <none needed in the general case> */ + if((snelmts = H5S_GET_SELECT_NPOINTS(dset_info[i].mem_space)) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dst dataspace has invalid selection") + H5_CHECKED_ASSIGN(nelmts, hsize_t, snelmts, hssize_t); - /* If space hasn't been allocated and not using external storage, - * return fill value to buffer if fill time is upon allocation, or - * do nothing if fill time is never. If the dataset is compact and - * fill time is NEVER, there is no way to tell whether part of data - * has been overwritten. So just proceed in reading. - */ - if(nelmts > 0 && dataset->shared->dcpl_cache.efl.nused == 0 && - !(*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage)) { - H5D_fill_value_t fill_status; /* Whether/How the fill value is defined */ - - /* Retrieve dataset's fill-value properties */ - if(H5P_is_fill_value_defined(&dataset->shared->dcpl_cache.fill, &fill_status) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined") - - /* Should be impossible, but check anyway... */ - if(fill_status == H5D_FILL_VALUE_UNDEFINED && - (dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC || dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET)) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "read failed: dataset doesn't exist, no data can be read") - - /* If we're never going to fill this dataset, just leave the junk in the user's buffer */ - if(dataset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_NEVER) - HGOTO_DONE(SUCCEED) - - /* Go fill the user's selection with the dataset's fill value */ - if(H5D__fill(dataset->shared->dcpl_cache.fill.buf, dataset->shared->type, buf, - type_info.mem_type, mem_space, dxpl_id) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "filling buf failed") - else - HGOTO_DONE(SUCCEED) - } /* end if */ + /* Make certain that the number of elements in each selection is the same */ + if(nelmts != (hsize_t)H5S_GET_SELECT_NPOINTS(dset_info[i].file_space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src and dest dataspace have different sizes") - /* Set up I/O operation */ - io_info.op_type = H5D_IO_OP_READ; - io_info.u.rbuf = buf; - if(H5D__ioinfo_init(dataset, dxpl_cache, dxpl_id, &type_info, &store, &io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation") - io_info_init = TRUE; + /* Check for a NULL buffer, after the H5S_ALL dataspace selection has been handled */ + if(NULL == dset_info[i].u.rbuf) { + /* Check for any elements selected (which is invalid) */ + if(nelmts > 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer") - /* Sanity check that space is allocated, if there are elements */ - if(nelmts > 0) - HDassert((*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage) - || dataset->shared->dcpl_cache.efl.nused > 0 - || dataset->shared->layout.type == H5D_COMPACT); + /* If the buffer is nil, and 0 element is selected, make a fake buffer. + * This is for some MPI package like ChaMPIon on NCSA's tungsten which + * doesn't support this feature. + */ + dset_info[i].u.rbuf = &fake_char; + } /* end if */ + + /* Make sure that both selections have their extents set */ + if(!(H5S_has_extent(dset_info[i].file_space))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set") + if(!(H5S_has_extent(dset_info[i].mem_space))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set") + + /* H5S_select_shape_same() has been modified to accept topologically + * identical selections with different rank as having the same shape + * (if the most rapidly changing coordinates match up), but the I/O + * code still has difficulties with the notion. + * + * To solve this, we check to see if H5S_select_shape_same() returns + * true, and if the ranks of the mem and file spaces are different. + * If the are, construct a new mem space that is equivalent to the + * old mem space, and use that instead. + * + * Note that in general, this requires us to touch up the memory buffer + * as well. + */ + if(TRUE == H5S_select_shape_same(dset_info[i].mem_space, dset_info[i].file_space) && + H5S_GET_EXTENT_NDIMS(dset_info[i].mem_space) != H5S_GET_EXTENT_NDIMS(dset_info[i].file_space)) { + const void *adj_buf = NULL; /* Pointer to the location in buf corresponding */ + /* to the beginning of the projected mem space. */ + + /* Attempt to construct projected dataspace for memory dataspace */ + if(H5S_select_construct_projection(dset_info[i].mem_space, &(projected_mem_space[i]), + (unsigned)H5S_GET_EXTENT_NDIMS(dset_info[i].file_space), dset_info[i].u.rbuf, + (const void **)&adj_buf, + (hsize_t)dset_info[i].type_info.dst_type_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace") + HDassert(projected_mem_space[i]); + HDassert(adj_buf); + + /* Switch to using projected memory dataspace & adjusted buffer */ + dset_info[i].mem_space = projected_mem_space[i]; + dset_info[i].u.rbuf = (void *)adj_buf; + } /* end if */ - /* Allocate the chunk map */ - if(NULL == (fm = H5FL_CALLOC(H5D_chunk_map_t))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk map") + /* Retrieve dataset properties */ + /* <none needed in the general case> */ - /* Call storage method's I/O initialization routine */ - if(io_info.layout_ops.io_init && (*io_info.layout_ops.io_init)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") - io_op_init = TRUE; + /* If space hasn't been allocated and not using external storage, + * return fill value to buffer if fill time is upon allocation, or + * do nothing if fill time is never. If the dataset is compact and + * fill time is NEVER, there is no way to tell whether part of data + * has been overwritten. So just proceed in reading. + */ + if(nelmts > 0 && dset_info[i].dset->shared->dcpl_cache.efl.nused == 0 && + !(*dset_info[i].dset->shared->layout.ops->is_space_alloc)(&dset_info[i].dset->shared->layout.storage)) { + H5D_fill_value_t fill_status; /* Whether/How the fill value is defined */ + + /* Retrieve dataset's fill-value properties */ + if(H5P_is_fill_value_defined(&dset_info[i].dset->shared->dcpl_cache.fill, &fill_status) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined") + + /* Should be impossible, but check anyway... */ + if(fill_status == H5D_FILL_VALUE_UNDEFINED && + (dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_ALLOC || + dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_IFSET)) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "read failed: dataset doesn't exist, no data can be read") + + /* If we're never going to fill this dataset, just leave the junk in the user's buffer */ + if(dset_info[i].dset->shared->dcpl_cache.fill.fill_time == H5D_FILL_TIME_NEVER) + HGOTO_DONE(SUCCEED) + + /* Go fill the user's selection with the dataset's fill value */ + if(H5D__fill(dset_info[i].dset->shared->dcpl_cache.fill.buf, dset_info[i].dset->shared->type, + dset_info[i].u.rbuf, dset_info[i].type_info.mem_type, dset_info[i].mem_space, dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "filling buf failed") + else + HGOTO_DONE(SUCCEED) + } /* end if */ + + /* Set up I/O operation */ + io_info.op_type = H5D_IO_OP_READ; + if(H5D__ioinfo_init(dset_info[i].dset, dxpl_cache, dxpl_id, &(dset_info[i]), + &(store[i]), &io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to set up I/O operation") + io_info_init = TRUE; + + /* Sanity check that space is allocated, if there are elements */ + if(nelmts > 0) + HDassert((*dset_info[i].dset->shared->layout.ops->is_space_alloc) + (&dset_info[i].dset->shared->layout.storage) + || dset_info[i].dset->shared->dcpl_cache.efl.nused > 0 + || dset_info[i].dset->shared->layout.type == H5D_COMPACT); + + /* Call storage method's I/O initialization routine */ + /* Init io_info.dset_info[] and generate piece_info in skip list */ + if(dset_info[i].layout_ops.io_init && + (*dset_info[i].layout_ops.io_init)(&io_info, &(dset_info[i].type_info), nelmts, + dset_info[i].file_space, dset_info[i].mem_space, + &(dset_info[i])) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") + io_op_init++; + } /* end of for loop */ + + assert(type_info_init == count); + assert(io_op_init == count); #ifdef H5_HAVE_PARALLEL /* Adjust I/O info for any parallel I/O */ - if(H5D__ioinfo_adjust(&io_info, dataset, dxpl_id, file_space, mem_space, &type_info, fm) < 0) + if(H5D__ioinfo_adjust(count, &io_info, dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O") +#else + io_info.is_coll_broken = TRUE; #endif /*H5_HAVE_PARALLEL*/ /* Invoke correct "high level" I/O routine */ - if((*io_info.io_ops.multi_read)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") + /* If collective mode is broken, perform read IO in independent mode via + * single-dset path with looping. + * Multiple-dset path can not be called since it is not supported, so make + * detour through single-dset path */ + if(TRUE == io_info.is_coll_broken) { + haddr_t prev_tag = HADDR_UNDEF; + + /* Loop with serial & single-dset read IO path */ + for(i = 0; i < count; i++) { + /* set metadata tagging with dset oheader addr */ + if(H5AC_tag(io_info.md_dxpl_id, dset_info[i].dset->oloc.addr, &prev_tag) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + + io_info.dsets_info = &(dset_info[i]); + + if((*io_info.io_ops.multi_read)(&io_info, &(dset_info[i].type_info), nelmts, dset_info[i].file_space, + dset_info[i].mem_space, &dset_info[i]) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") + + /* Reset metadata tagging */ + if(H5AC_tag(io_info.md_dxpl_id, prev_tag, NULL) < 0) + HDONE_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + } + } /* end if */ + else + if((*io_info.io_ops.multi_read_md)(file_id, count, &io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read data") done: /* Shut down the I/O op information */ - if(io_op_init && io_info.layout_ops.io_term && (*io_info.layout_ops.io_term)(fm) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info") - if(fm) - fm = H5FL_FREE(H5D_chunk_map_t, fm); + for(i = 0; i < io_op_init; i++) + if(dset_info[i].layout_ops.io_term && (*dset_info[i].layout_ops.io_term)(&io_info, &(dset_info[i])) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info") + if(io_info_init) { #ifdef H5_DEBUG_BUILD @@ -614,40 +1008,52 @@ done: } /* Shut down datatype info for operation */ - if(type_info_init && H5D__typeinfo_term(&type_info) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info") + for(i = 0; i < type_info_init; i++) + if(H5D__typeinfo_term(&(dset_info[i].type_info)) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info") + + /* Discard projected mem spaces if they were created */ + for(i = 0; i < count; i++) + if(NULL != projected_mem_space[i]) + if(H5S_close(projected_mem_space[i]) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down projected memory dataspace") + + /* Free global piece skiplist */ + if(io_info.sel_pieces) + if(H5SL_close(io_info.sel_pieces) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't close dataset skip list") + + /* io_info.dsets_info was allocated in calling function */ + if(projected_mem_space) + H5MM_xfree(projected_mem_space); + if(store) + H5MM_xfree(store); - /* discard projected mem space if it was created */ - if(NULL != projected_mem_space) - if(H5S_close(projected_mem_space) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down projected memory dataspace") - - FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__read() */ /*------------------------------------------------------------------------- * Function: H5D__write * - * Purpose: Writes (part of) a DATASET to a file from application memory - * BUF. See H5Dwrite() for complete details. + * Purpose: Writes multiple (part of) DATASETs to a file from application + * memory BUFs. See H5Dwrite_multi() for complete details. + * + * This was referred from H5D__write for multi-dset work. * * Return: Non-negative on success/Negative on failure * - * Programmer: Robb Matzke - * Thursday, December 4, 1997 + * Programmer: Jonathan Kim Nov, 2013 * *------------------------------------------------------------------------- */ herr_t -H5D__write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, - const H5S_t *file_space, hid_t dxpl_id, const void *buf) -{ - H5D_chunk_map_t *fm = NULL; /* Chunk file<->memory mapping */ - H5D_io_info_t io_info; /* Dataset I/O info */ - H5D_type_info_t type_info; /* Datatype info for operation */ - hbool_t type_info_init = FALSE; /* Whether the datatype info has been initialized */ - H5S_t * projected_mem_space = NULL; /* If not NULL, ptr to dataspace containing a */ +H5D__write(hid_t file_id, hid_t dxpl_id, size_t count, + H5D_dset_info_t *dset_info) +{ + H5D_io_info_t io_info; /* Dataset I/O info for multi dsets */ + size_t type_info_init = 0; /* Number of datatype info structs that have been initialized */ + H5S_t **projected_mem_space = NULL; /* If not NULL, ptr to dataspace containing a */ /* projection of the supplied mem_space to a new */ /* data space with rank equal to that of */ /* file_space. */ @@ -660,180 +1066,259 @@ H5D__write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, /* Note that if this variable is used, the */ /* projected mem space must be discarded at the */ /* end of the function to avoid a memory leak. */ - H5D_storage_t store; /*union of EFL and chunk pointer in file space */ - hssize_t snelmts; /*total number of elmts (signed) */ - hsize_t nelmts; /*total number of elmts */ + H5D_storage_t *store = NULL; /* Union of EFL and chunk pointer in file space */ + hssize_t snelmts; /* Total number of elmts (signed) */ + hsize_t nelmts; /* Total number of elmts */ hbool_t io_info_init = FALSE; /* Whether the I/O info has been initialized */ - hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */ + size_t io_op_init = 0; /* Number I/O ops that have been initialized */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ + size_t i; /* Local index variable */ char fake_char; /* Temporary variable for NULL buffer pointers */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_PACKAGE_TAG(dxpl_id, dataset->oloc.addr, FAIL) + FUNC_ENTER_NOAPI(FAIL) - /* check args */ - HDassert(dataset && dataset->oloc.file); + /* Init io_info */ + io_info.sel_pieces = NULL; + io_info.store_faddr = 0; + io_info.base_maddr_w = NULL; - /* All filters in the DCPL must have encoding enabled. */ - if(!dataset->shared->checked_filters) { - if(H5Z_can_apply(dataset->shared->dcpl_id, dataset->shared->type_id) < 0) - HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters") + /* Create global piece skiplist */ + if(NULL == (io_info.sel_pieces = H5SL_create(H5SL_TYPE_HADDR, NULL))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "can't create skip list for piece selections") - dataset->shared->checked_filters = TRUE; - } /* end if */ + /* Use provided dset_info */ + io_info.dsets_info = dset_info; + + /* Allocate other buffers */ + if(NULL == (projected_mem_space = (H5S_t **)H5MM_calloc(count * sizeof(H5S_t*)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "couldn't allocate dset space array ptr") + if(NULL == (store = (H5D_storage_t *)H5MM_malloc(count * sizeof(H5D_storage_t)))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTALLOC, FAIL, "couldn't allocate dset storage info array buffer") + + /* init both dxpls to the original one */ + io_info.md_dxpl_id = dxpl_id; + io_info.raw_dxpl_id = dxpl_id; + + /* set the dxpl IO type for sanity checking at the FD layer */ +#ifdef H5_DEBUG_BUILD + if(H5D_set_io_info_dxpls(&io_info, dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't set metadata and raw data dxpls") +#endif /* H5_DEBUG_BUILD */ + + /* iterate over all dsets and construct I/O information */ + for(i = 0; i < count; i++) { + haddr_t prev_tag = HADDR_UNDEF; + + /* check args */ + if(NULL == dset_info[i].dset) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset") + if(NULL == dset_info[i].dset->oloc.file) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") - /* Check if we are allowed to write to this file */ - if(0 == (H5F_INTENT(dataset->oloc.file) & H5F_ACC_RDWR)) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file") + /* set metadata tagging with dset oheader addr */ + if(H5AC_tag(io_info.md_dxpl_id, dset_info[i].dset->oloc.addr, &prev_tag) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") - /* Fill the DXPL cache values for later use */ - if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") + /* All filters in the DCPL must have encoding enabled. */ + if(!dset_info[i].dset->shared->checked_filters) { + if(H5Z_can_apply(dset_info[i].dset->shared->dcpl_id, dset_info[i].dset->shared->type_id) < 0) + HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "can't apply filters") - /* Set up datatype info for operation */ - if(H5D__typeinfo_init(dataset, dxpl_cache, dxpl_id, mem_type_id, TRUE, &type_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info") - type_info_init = TRUE; + dset_info[i].dset->shared->checked_filters = TRUE; + } /* end if */ + + /* Check if we are allowed to write to this file */ + if(0 == (H5F_INTENT(dset_info[i].dset->oloc.file) & H5F_ACC_RDWR)) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "no write intent on file") + + /* Fill the DXPL cache values for later use */ + if(H5D__get_dxpl_cache(dxpl_id, &dxpl_cache) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") + + /* Set up datatype info for operation */ + if(H5D__typeinfo_init(dset_info[i].dset, dxpl_cache, dxpl_id, dset_info[i].mem_type_id, + TRUE, &(dset_info[i].type_info)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up type info") + type_info_init++; /* Various MPI based checks */ #ifdef H5_HAVE_PARALLEL - if H5F_HAS_FEATURE(dataset->oloc.file, H5FD_FEAT_HAS_MPI) { - /* If MPI based VFD is used, no VL datatype support yet. */ - /* This is because they use the global heap in the file and we don't */ - /* support parallel access of that yet */ - if(H5T_detect_class(type_info.mem_type, H5T_VLEN, FALSE) > 0) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Parallel IO does not support writing VL datatypes yet") - - /* If MPI based VFD is used, no VL datatype support yet. */ - /* This is because they use the global heap in the file and we don't */ - /* support parallel access of that yet */ - /* We should really use H5T_detect_class() here, but it will be difficult - * to detect the type of the reference if it is nested... -QAK - */ - if(H5T_get_class(type_info.mem_type, TRUE) == H5T_REFERENCE && - H5T_get_ref_type(type_info.mem_type) == H5R_DATASET_REGION) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Parallel IO does not support writing region reference datatypes yet") - } /* end if */ - else { - /* Collective access is not permissible without a MPI based VFD */ - if(dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) - HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based driver only") - } /* end else */ + if H5F_HAS_FEATURE(dset_info[i].dset->oloc.file, H5FD_FEAT_HAS_MPI) { + /* If MPI based VFD is used, no VL datatype support yet. */ + /* This is because they use the global heap in the file and we don't */ + /* support parallel access of that yet */ + if(H5T_detect_class(dset_info[i].type_info.mem_type, H5T_VLEN, FALSE) > 0) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Parallel IO does not support writing VL datatypes yet") + + /* If MPI based VFD is used, no VL datatype support yet. */ + /* This is because they use the global heap in the file and we don't */ + /* support parallel access of that yet */ + /* We should really use H5T_detect_class() here, but it will be difficult + * to detect the type of the reference if it is nested... -QAK + */ + if(H5T_get_class(dset_info[i].type_info.mem_type, TRUE) == H5T_REFERENCE && + H5T_get_ref_type(dset_info[i].type_info.mem_type) == H5R_DATASET_REGION) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "Parallel IO does not support writing region reference datatypes yet") + + /* Can't write to chunked datasets with filters, in parallel */ + if(dset_info[i].dset->shared->layout.type == H5D_CHUNKED && + dset_info[i].dset->shared->dcpl_cache.pline.nused > 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot write to chunked storage with filters in parallel") + } /* end if */ + else { + /* Collective access is not permissible without a MPI based VFD */ + if(dxpl_cache->xfer_mode == H5FD_MPIO_COLLECTIVE) + HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "collective access for MPI-based driver only") + } /* end else */ #endif /*H5_HAVE_PARALLEL*/ - /* Initialize dataspace information */ - if(!file_space) - file_space = dataset->shared->space; - if(!mem_space) - mem_space = file_space; + if((snelmts = H5S_GET_SELECT_NPOINTS(dset_info[i].mem_space)) < 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src dataspace has invalid selection") + H5_CHECKED_ASSIGN(nelmts, hsize_t, snelmts, hssize_t); - if((snelmts = H5S_GET_SELECT_NPOINTS(mem_space)) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src dataspace has invalid selection") - H5_CHECKED_ASSIGN(nelmts, hsize_t, snelmts, hssize_t); + /* Make certain that the number of elements in each selection is the same */ + if(nelmts != (hsize_t)H5S_GET_SELECT_NPOINTS(dset_info[i].file_space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src and dest data space have different sizes") - /* Make certain that the number of elements in each selection is the same */ - if(nelmts != (hsize_t)H5S_GET_SELECT_NPOINTS(file_space)) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src and dest data spaces have different sizes") + /* Check for a NULL buffer, after the H5S_ALL dataspace selection has been handled */ + if(NULL == dset_info[i].u.wbuf) { + /* Check for any elements selected (which is invalid) */ + if(nelmts > 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer") - /* Check for a NULL buffer, after the H5S_ALL dataspace selection has been handled */ - if(NULL == buf) { - /* Check for any elements selected (which is invalid) */ - if(nelmts > 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no output buffer") + /* If the buffer is nil, and 0 element is selected, make a fake buffer. + * This is for some MPI package like ChaMPIon on NCSA's tungsten which + * doesn't support this feature. + */ + dset_info[i].u.wbuf = &fake_char; + } /* end if */ - /* If the buffer is nil, and 0 element is selected, make a fake buffer. - * This is for some MPI package like ChaMPIon on NCSA's tungsten which - * doesn't support this feature. - */ - buf = &fake_char; - } /* end if */ + /* Make sure that both selections have their extents set */ + if(!(H5S_has_extent(dset_info[i].file_space))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set") + if(!(H5S_has_extent(dset_info[i].mem_space))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set") + + /* H5S_select_shape_same() has been modified to accept topologically + * identical selections with different rank as having the same shape + * (if the most rapidly changing coordinates match up), but the I/O + * code still has difficulties with the notion. + * + * To solve this, we check to see if H5S_select_shape_same() returns + * true, and if the ranks of the mem and file spaces are different. + * If the are, construct a new mem space that is equivalent to the + * old mem space, and use that instead. + * + * Note that in general, this requires us to touch up the memory buffer + * as well. + */ + if(TRUE == H5S_select_shape_same(dset_info[i].mem_space, dset_info[i].file_space) && + H5S_GET_EXTENT_NDIMS(dset_info[i].mem_space) != H5S_GET_EXTENT_NDIMS(dset_info[i].file_space)) { + const void *adj_buf = NULL; /* Pointer to the location in buf corresponding */ + /* to the beginning of the projected mem space. */ + + /* Attempt to construct projected dataspace for memory dataspace */ + if(H5S_select_construct_projection(dset_info[i].mem_space, &(projected_mem_space[i]), + (unsigned)H5S_GET_EXTENT_NDIMS(dset_info[i].file_space), + dset_info[i].u.wbuf, (const void **)&adj_buf, + (hsize_t)dset_info[i].type_info.src_type_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace") + HDassert(projected_mem_space[i]); + HDassert(adj_buf); + + /* Switch to using projected memory dataspace & adjusted buffer */ + dset_info[i].mem_space = projected_mem_space[i]; + dset_info[i].u.wbuf = adj_buf; + } /* end if */ - /* Make sure that both selections have their extents set */ - if(!(H5S_has_extent(file_space))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file dataspace does not have extent set") - if(!(H5S_has_extent(mem_space))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "memory dataspace does not have extent set") - - /* H5S_select_shape_same() has been modified to accept topologically - * identical selections with different rank as having the same shape - * (if the most rapidly changing coordinates match up), but the I/O - * code still has difficulties with the notion. - * - * To solve this, we check to see if H5S_select_shape_same() returns - * true, and if the ranks of the mem and file spaces are different. - * If the are, construct a new mem space that is equivalent to the - * old mem space, and use that instead. - * - * Note that in general, this requires us to touch up the memory buffer - * as well. - */ - if(TRUE == H5S_select_shape_same(mem_space, file_space) && - H5S_GET_EXTENT_NDIMS(mem_space) != H5S_GET_EXTENT_NDIMS(file_space)) { - void *adj_buf = NULL; /* Pointer to the location in buf corresponding */ - /* to the beginning of the projected mem space. */ - - /* Attempt to construct projected dataspace for memory dataspace */ - if(H5S_select_construct_projection(mem_space, &projected_mem_space, - (unsigned)H5S_GET_EXTENT_NDIMS(file_space), buf, (const void **)&adj_buf, type_info.src_type_size) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to construct projected memory dataspace") - HDassert(projected_mem_space); - HDassert(adj_buf); - - /* Switch to using projected memory dataspace & adjusted buffer */ - mem_space = projected_mem_space; - buf = adj_buf; - } /* end if */ + /* Retrieve dataset properties */ + /* <none needed currently> */ - /* Retrieve dataset properties */ - /* <none needed currently> */ - - /* Set up I/O operation */ - io_info.op_type = H5D_IO_OP_WRITE; - io_info.u.wbuf = buf; - if(H5D__ioinfo_init(dataset, dxpl_cache, dxpl_id, &type_info, &store, &io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up I/O operation") - io_info_init = TRUE; - - /* Allocate data space and initialize it if it hasn't been. */ - if(nelmts > 0 && dataset->shared->dcpl_cache.efl.nused == 0 && - !(*dataset->shared->layout.ops->is_space_alloc)(&dataset->shared->layout.storage)) { - hssize_t file_nelmts; /* Number of elements in file dataset's dataspace */ - hbool_t full_overwrite; /* Whether we are over-writing all the elements */ - - /* Get the number of elements in file dataset's dataspace */ - if((file_nelmts = H5S_GET_EXTENT_NPOINTS(file_space)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "can't retrieve number of elements in file dataset") - - /* Always allow fill values to be written if the dataset has a VL datatype */ - if(H5T_detect_class(dataset->shared->type, H5T_VLEN, FALSE)) - full_overwrite = FALSE; - else - full_overwrite = (hbool_t)((hsize_t)file_nelmts == nelmts ? TRUE : FALSE); - - /* Allocate storage */ - if(H5D__alloc_storage(&io_info, H5D_ALLOC_WRITE, full_overwrite, NULL) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage") - } /* end if */ + /* Set up I/O operation */ + io_info.op_type = H5D_IO_OP_WRITE; + if(H5D__ioinfo_init(dset_info[i].dset, dxpl_cache, dxpl_id, &(dset_info[i]), + &(store[i]), &io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to set up I/O operation") +#ifdef H5_HAVE_PARALLEL + io_info_init = TRUE; +#endif /*H5_HAVE_PARALLEL*/ - /* Allocate the chunk map */ - if(NULL == (fm = H5FL_CALLOC(H5D_chunk_map_t))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk map") + /* Allocate dataspace and initialize it if it hasn't been. */ + if(nelmts > 0 && dset_info[i].dset->shared->dcpl_cache.efl.nused == 0 && + !(*dset_info[i].dset->shared->layout.ops->is_space_alloc)(&dset_info[i].dset->shared->layout.storage)) { + hssize_t file_nelmts; /* Number of elements in file dataset's dataspace */ + hbool_t full_overwrite; /* Whether we are over-writing all the elements */ + + /* Get the number of elements in file dataset's dataspace */ + if((file_nelmts = H5S_GET_EXTENT_NPOINTS(dset_info[i].file_space)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "can't retrieve number of elements in file dataset") + + /* Always allow fill values to be written if the dataset has a VL datatype */ + if(H5T_detect_class(dset_info[i].dset->shared->type, H5T_VLEN, FALSE)) + full_overwrite = FALSE; + else + full_overwrite = (hbool_t)((hsize_t)file_nelmts == nelmts ? TRUE : FALSE); + + io_info.dset = dset_info[i].dset; + /* Allocate storage */ + if(H5D__alloc_storage(&io_info, H5D_ALLOC_WRITE, full_overwrite, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage") + } /* end if */ - /* Call storage method's I/O initialization routine */ - if(io_info.layout_ops.io_init && (*io_info.layout_ops.io_init)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") - io_op_init = TRUE; + /* Call storage method's I/O initialization routine */ + /* Init io_info.dset_info[] and generate piece_info in skip list */ + if(dset_info[i].layout_ops.io_init && + (*dset_info[i].layout_ops.io_init)(&io_info, &(dset_info[i].type_info), nelmts, + dset_info[i].file_space, dset_info[i].mem_space, + &(dset_info[i])) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize I/O info") + io_op_init++; + + /* Reset metadata tagging */ + if(H5AC_tag(io_info.md_dxpl_id, prev_tag, NULL) < 0) + HDONE_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + } /* end of Count for loop */ + assert(type_info_init == count); + assert(io_op_init == count); #ifdef H5_HAVE_PARALLEL /* Adjust I/O info for any parallel I/O */ - if(H5D__ioinfo_adjust(&io_info, dataset, dxpl_id, file_space, mem_space, &type_info, fm) < 0) + if(H5D__ioinfo_adjust(count, &io_info, dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to adjust I/O info for parallel I/O") +#else + io_info.is_coll_broken = TRUE; #endif /*H5_HAVE_PARALLEL*/ - /* Invoke correct "high level" I/O routine */ - if((*io_info.io_ops.multi_write)(&io_info, &type_info, nelmts, file_space, mem_space, fm) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") + /* If collective mode is broken, perform write IO in independent mode via + * single-dset path with looping. + * Multiple-dset path can not be called since it is not supported, so make + * detour through single-dset path */ + if(TRUE == io_info.is_coll_broken) { + haddr_t prev_tag = HADDR_UNDEF; + + /* loop with serial & single-dset write IO path */ + for(i = 0; i < count; i++) { + /* set metadata tagging with dset oheader addr */ + if(H5AC_tag(io_info.md_dxpl_id, dset_info->dset->oloc.addr, &prev_tag) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + + io_info.dsets_info = &(dset_info[i]); + + /* Invoke correct "high level" I/O routine */ + if((*io_info.io_ops.multi_write)(&io_info, &(dset_info[i].type_info), nelmts, dset_info[i].file_space, + dset_info[i].mem_space, &dset_info[i]) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") + /* Reset metadata tagging */ + if(H5AC_tag(io_info.md_dxpl_id, prev_tag, NULL) < 0) + HDONE_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "unable to apply metadata tag") + } + } /* end if */ + else + /* Invoke correct "high level" I/O routine */ + if((*io_info.io_ops.multi_write_md)(file_id, count, &io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write data") #ifdef OLD_WAY /* @@ -855,10 +1340,10 @@ H5D__write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, done: /* Shut down the I/O op information */ - if(io_op_init && io_info.layout_ops.io_term && (*io_info.layout_ops.io_term)(fm) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info") - if(fm) - fm = H5FL_FREE(H5D_chunk_map_t, fm); + for(i = 0; i < io_op_init; i++) + if(dset_info[i].layout_ops.io_term && (*dset_info[i].layout_ops.io_term)(&io_info, &(dset_info[i])) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down I/O op info") + if(io_info_init) { #ifdef H5_DEBUG_BUILD @@ -874,38 +1359,50 @@ done: } /* Shut down datatype info for operation */ - if(type_info_init && H5D__typeinfo_term(&type_info) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info") + for(i = 0; i < type_info_init; i++) + if(H5D__typeinfo_term(&(dset_info[i].type_info)) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down type info") + + /* Discard projected mem spaces if they were created */ + for(i = 0; i < count; i++) + if(NULL != projected_mem_space[i]) + if(H5S_close(projected_mem_space[i]) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down projected memory dataspace") + + /* Free global piece skiplist */ + if(io_info.sel_pieces) + if(H5SL_close(io_info.sel_pieces) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't close dataset skip list") + + /* io_info.dsets_info was allocated in calling function */ + if(projected_mem_space) + H5MM_xfree(projected_mem_space); + if(store) + H5MM_xfree(store); - /* discard projected mem space if it was created */ - if(NULL != projected_mem_space) - if(H5S_close(projected_mem_space) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "unable to shut down projected memory dataspace") - - FUNC_LEAVE_NOAPI_TAG(ret_value, FAIL) -} /* end H5D__write() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__write */ /*------------------------------------------------------------------------- * Function: H5D__ioinfo_init * - * Purpose: Routine for determining correct I/O operations for - * each I/O action. + * Purpose: Routine for determining correct I/O operations for each I/O action. * - * Return: Non-negative on success/Negative on failure + * This was derived from H5D__ioinfo_init for multi-dset work. * - * Programmer: Quincey Koziol - * Thursday, September 30, 2004 + * Return: Non-negative on success/Negative on failure * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ static herr_t H5D__ioinfo_init(H5D_t *dset, #ifndef H5_HAVE_PARALLEL -const + const #endif /* H5_HAVE_PARALLEL */ - H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, - const H5D_type_info_t *type_info, H5D_storage_t *store, H5D_io_info_t *io_info) + H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, + H5D_dset_info_t *dset_info, H5D_storage_t *store, H5D_io_info_t *io_info) { herr_t ret_value = SUCCEED; @@ -914,34 +1411,25 @@ const /* check args */ HDassert(dset); HDassert(dset->oloc.file); - HDassert(type_info); - HDassert(type_info->tpath); + //HDassert(&(dset_info->type_info)); + HDassert(dset_info->type_info.tpath); HDassert(io_info); - /* init both dxpls to the original one */ - io_info->md_dxpl_id = dxpl_id; - io_info->raw_dxpl_id = dxpl_id; - - /* set the dxpl IO type for sanity checking at the FD layer */ -#ifdef H5_DEBUG_BUILD - if(H5D_set_io_info_dxpls(io_info, dxpl_id) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "can't set metadata and raw data dxpls") -#endif /* H5_DEBUG_BUILD */ - /* Set up "normal" I/O fields */ - io_info->dset = dset; + dset_info->dset = dset; io_info->dxpl_cache = dxpl_cache; - io_info->store = store; + io_info->is_coll_broken = FALSE; /* is collective broken? */ + dset_info->store = store; /* Set I/O operations to initial values */ - io_info->layout_ops = *dset->shared->layout.ops; + dset_info->layout_ops = *dset->shared->layout.ops; /* Set the "high-level" I/O operations for the dataset */ io_info->io_ops.multi_read = dset->shared->layout.ops->ser_read; io_info->io_ops.multi_write = dset->shared->layout.ops->ser_write; /* Set the I/O operations for reading/writing single blocks on disk */ - if(type_info->is_xform_noop && type_info->is_conv_noop) { + if(dset_info->type_info.is_xform_noop && dset_info->type_info.is_conv_noop) { /* * If there is no data transform or type conversion then read directly into * the application's buffer. This saves at least one mem-to-mem copy. @@ -1133,18 +1621,17 @@ done: * * Purpose: Adjust operation's I/O info for any parallel I/O * - * Return: Non-negative on success/Negative on failure + * This was derived from H5D__ioinfo_adjust for multi-dset work. * - * Programmer: Quincey Koziol - * Thursday, March 27, 2008 + * Return: Non-negative on success/Negative on failure * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ static herr_t -H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, hid_t dxpl_id, - const H5S_t *file_space, const H5S_t *mem_space, - const H5D_type_info_t *type_info, const H5D_chunk_map_t *fm) +H5D__ioinfo_adjust(const size_t count, H5D_io_info_t *io_info, hid_t dxpl_id) { + H5D_t *dset0; /* only the first dset , also for single dsets case */ H5P_genplist_t *dx_plist; /* Data transer property list */ H5D_mpio_actual_chunk_opt_mode_t actual_chunk_opt_mode; /* performed chunk optimization */ H5D_mpio_actual_io_mode_t actual_io_mode; /* performed io mode */ @@ -1153,14 +1640,14 @@ H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, hid_t dxpl_id, FUNC_ENTER_STATIC /* check args */ - HDassert(dset); - HDassert(dset->oloc.file); - HDassert(mem_space); - HDassert(file_space); - HDassert(type_info); - HDassert(type_info->tpath); + HDassert(count > 0); HDassert(io_info); + /* check the first dset, should exist either single or multi dset cases */ + HDassert(io_info->dsets_info[0].dset); + dset0 = io_info->dsets_info[0].dset; + HDassert(dset0->oloc.file); + /* Get the dataset transfer property list */ if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(dxpl_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") @@ -1182,87 +1669,32 @@ H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, hid_t dxpl_id, /* Record the original state of parallel I/O transfer options */ io_info->orig.xfer_mode = io_info->dxpl_cache->xfer_mode; io_info->orig.coll_opt_mode = io_info->dxpl_cache->coll_opt_mode; + /* single-dset */ io_info->orig.io_ops.single_read = io_info->io_ops.single_read; io_info->orig.io_ops.single_write = io_info->io_ops.single_write; + /* multi-dset */ + io_info->orig.io_ops.single_read_md = io_info->io_ops.single_read_md; + io_info->orig.io_ops.single_write_md = io_info->io_ops.single_write_md; - /* Get MPI communicator */ - if(MPI_COMM_NULL == (io_info->comm = H5F_mpi_get_comm(dset->oloc.file))) + /* Get MPI communicator from the first dset */ + if(MPI_COMM_NULL == (io_info->comm = H5F_mpi_get_comm(dset0->oloc.file))) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't retrieve MPI communicator") /* Check if we can set direct MPI-IO read/write functions */ - if((opt = H5D__mpio_opt_possible(io_info, file_space, mem_space, type_info, dx_plist)) < 0) + if((opt = H5D__mpio_opt_possible(count, io_info, dx_plist)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for direct IO dataspace ") /* Check if we can use the optimized parallel I/O routines */ if(opt == TRUE) { /* Override the I/O op pointers to the MPI-specific routines */ - io_info->io_ops.multi_read = dset->shared->layout.ops->par_read; - io_info->io_ops.multi_write = dset->shared->layout.ops->par_write; - io_info->io_ops.single_read = H5D__mpio_select_read; - io_info->io_ops.single_write = H5D__mpio_select_write; + io_info->io_ops.multi_read = NULL; + io_info->io_ops.multi_write = NULL; + io_info->io_ops.multi_read_md = dset0->shared->layout.ops->par_read; + io_info->io_ops.multi_write_md = dset0->shared->layout.ops->par_write; + io_info->io_ops.single_read_md = H5D__mpio_select_read; + io_info->io_ops.single_write_md = H5D__mpio_select_write; } /* end if */ else { - /* Check if there are any filters in the pipeline. If there are, - * we cannot break to independent I/O if this is a write operation; - * otherwise there will be metadata inconsistencies in the file. - */ - if (io_info->op_type == H5D_IO_OP_WRITE && io_info->dset->shared->dcpl_cache.pline.nused > 0) { - H5D_mpio_no_collective_cause_t cause; - uint32_t local_no_collective_cause; - uint32_t global_no_collective_cause; - hbool_t local_error_message_previously_written = FALSE; - hbool_t global_error_message_previously_written = FALSE; - size_t index; - char local_no_collective_cause_string[256] = ""; - char global_no_collective_cause_string[256] = ""; - const char *cause_strings[] = { "independent I/O was requested", - "datatype conversions were required", - "data transforms needed to be applied", - "optimized MPI types flag wasn't set", - "one of the dataspaces was neither simple nor scalar", - "dataset was not contiguous or chunked" }; - - if (H5P_get(dx_plist, H5D_MPIO_LOCAL_NO_COLLECTIVE_CAUSE_NAME, &local_no_collective_cause) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get local no collective cause value") - if (H5P_get(dx_plist, H5D_MPIO_GLOBAL_NO_COLLECTIVE_CAUSE_NAME, &global_no_collective_cause) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get global no collective cause value") - - /* Append each of the "reason for breaking collective I/O" error messages to the - * local and global no collective cause strings */ - for (cause = 1, index = 0; cause < H5D_MPIO_NO_COLLECTIVE_MAX_CAUSE; cause <<= 1, index++) { - size_t cause_strlen = strlen(cause_strings[index]); - - if (cause & local_no_collective_cause) { - /* Check if there were any previous error messages included. If so, prepend a semicolon - * to separate the messages. - */ - if (local_error_message_previously_written) strncat(local_no_collective_cause_string, "; ", 2); - - strncat(local_no_collective_cause_string, cause_strings[index], cause_strlen); - - local_error_message_previously_written = TRUE; - } /* end if */ - - if (cause & global_no_collective_cause) { - /* Check if there were any previous error messages included. If so, prepend a semicolon - * to separate the messages. - */ - if (global_error_message_previously_written) strncat(global_no_collective_cause_string, "; ", 2); - - strncat(global_no_collective_cause_string, cause_strings[index], cause_strlen); - - global_error_message_previously_written = TRUE; - } /* end if */ - } /* end for */ - - HGOTO_ERROR(H5E_IO, H5E_NO_INDEPENDENT, FAIL, "Can't perform independent write with filters in pipeline.\n" - " The following caused a break from collective I/O:\n" - " Local causes: %s\n" - " Global causes: %s", - local_no_collective_cause_string, - global_no_collective_cause_string); - } /* end if */ - /* If we won't be doing collective I/O, but the user asked for * collective I/O, change the request to use independent I/O, but * mark it so that we remember to revert the change. @@ -1272,10 +1704,14 @@ H5D__ioinfo_adjust(H5D_io_info_t *io_info, const H5D_t *dset, hid_t dxpl_id, io_info->dxpl_cache->xfer_mode = H5FD_MPIO_INDEPENDENT; if(H5P_set(dx_plist, H5D_XFER_IO_XFER_MODE_NAME, &io_info->dxpl_cache->xfer_mode) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set transfer mode") + io_info->is_coll_broken = TRUE; } /* end if */ + else if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_INDEPENDENT) + io_info->is_coll_broken = TRUE; } /* end else */ } /* end if */ - + else + io_info->is_coll_broken = TRUE; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__ioinfo_adjust() */ @@ -1285,13 +1721,13 @@ done: * Function: H5D__ioinfo_term * * Purpose: Common logic for terminating an I/O info object - * (Only used for restoring MPI transfer mode currently) + * (Only used for restoring MPI transfer mode currently) * - * Return: Non-negative on success/Negative on failure + * This was derived from H5D__ioinfo_term for multi-dset work. * - * Programmer: Quincey Koziol - * Friday, February 6, 2004 + * Return: Non-negative on success/Negative on failure * + * Programmer: Jonathan Kim Nov, 2013 *------------------------------------------------------------------------- */ static herr_t diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index 79572c0..961a49e 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -87,10 +87,12 @@ /******************/ /* Local Typedefs */ /******************/ -/* Combine chunk address and chunk info into a struct for better performance. */ +/* Combine chunk/piece address and chunk/piece info into a struct for + * better performance. */ typedef struct H5D_chunk_addr_info_t { - haddr_t chunk_addr; - H5D_chunk_info_t chunk_info; + /* piece for multi-dset */ + haddr_t piece_addr; + H5D_chunk_info_t piece_info; } H5D_chunk_addr_info_t; /* @@ -204,6 +206,15 @@ typedef struct H5D_filtered_collective_io_info_t { /********************/ /* Local Prototypes */ /********************/ +/* multi-dset IO */ +static herr_t H5D__piece_io(const hid_t file_id, const size_t count, + H5D_io_info_t *io_info); +static herr_t H5D__final_collective_io_md(H5D_io_info_t *io_info, + hsize_t mpi_buf_count, MPI_Datatype *mpi_file_type, MPI_Datatype *mpi_buf_type); + +static herr_t H5D__all_piece_collective_io(const hid_t file_id, const size_t count, + H5D_io_info_t *io_info, H5P_genplist_t *dx_plist); + static herr_t H5D__chunk_collective_io(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, H5D_chunk_map_t *fm); static herr_t H5D__multi_chunk_collective_io(H5D_io_info_t *io_info, @@ -272,20 +283,24 @@ static int H5D__cmp_filtered_collective_io_info_entry_owner(const void *filtered * Function: H5D__mpio_opt_possible * * Purpose: Checks if an direct I/O transfer is possible between memory and - * the file. + * the file. + * + * This was derived from H5D__mpio_opt_possible for + * multi-dset work. * * Return: Success: Non-negative: TRUE or FALSE * Failure: Negative * - * Programmer: Quincey Koziol - * Wednesday, April 3, 2002 - * *------------------------------------------------------------------------- */ htri_t -H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, - const H5S_t *mem_space, const H5D_type_info_t *type_info, H5P_genplist_t *dx_plist) +H5D__mpio_opt_possible(const size_t count, H5D_io_info_t *io_info, H5P_genplist_t *dx_plist) { + int i; + H5D_t *dset; + H5S_t *file_space; + const H5S_t *mem_space; + H5D_type_info_t type_info; int local_cause = 0; /* Local reason(s) for breaking collective mode */ int global_cause = 0; /* Global reason(s) for breaking collective mode */ htri_t ret_value = SUCCEED; /* Return value */ @@ -294,48 +309,59 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, /* Check args */ HDassert(io_info); - HDassert(mem_space); - HDassert(file_space); - HDassert(type_info); + HDassert(dx_plist); /* For independent I/O, get out quickly and don't try to form consensus */ if(io_info->dxpl_cache->xfer_mode == H5FD_MPIO_INDEPENDENT) local_cause |= H5D_MPIO_SET_INDEPENDENT; - /* Optimized MPI types flag must be set */ - /* (based on 'HDF5_MPI_OPT_TYPES' environment variable) */ - if(!H5FD_mpi_opt_types_g) - local_cause |= H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED; - - /* Don't allow collective operations if datatype conversions need to happen */ - if(!type_info->is_conv_noop) - local_cause |= H5D_MPIO_DATATYPE_CONVERSION; - - /* Don't allow collective operations if data transform operations should occur */ - if(!type_info->is_xform_noop) - local_cause |= H5D_MPIO_DATA_TRANSFORMS; - - /* Check whether these are both simple or scalar dataspaces */ - if(!((H5S_SIMPLE == H5S_GET_EXTENT_TYPE(mem_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(mem_space)) - && (H5S_SIMPLE == H5S_GET_EXTENT_TYPE(file_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(file_space)))) - local_cause |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES; - - /* Dataset storage must be contiguous or chunked */ - if(!(io_info->dset->shared->layout.type == H5D_CONTIGUOUS || - io_info->dset->shared->layout.type == H5D_CHUNKED)) - local_cause |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; - - /* check if external-file storage is used */ - if(io_info->dset->shared->dcpl_cache.efl.nused > 0) - local_cause |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; - - /* The handling of memory space is different for chunking and contiguous - * storage. For contiguous storage, mem_space and file_space won't change - * when it it is doing disk IO. For chunking storage, mem_space will - * change for different chunks. So for chunking storage, whether we can - * use collective IO will defer until each chunk IO is reached. - */ + for (i = 0; i < count; i++) + { + dset = io_info->dsets_info[i].dset; + file_space = io_info->dsets_info[i].file_space; + mem_space = io_info->dsets_info[i].mem_space; + type_info = io_info->dsets_info[i].type_info; + + /* Optimized MPI types flag must be set */ + /* (based on 'HDF5_MPI_OPT_TYPES' environment variable) */ + if(!H5FD_mpi_opt_types_g) + local_cause |= H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED; + + /* Don't allow collective operations if datatype conversions need to happen */ + if(!type_info.is_conv_noop) + local_cause |= H5D_MPIO_DATATYPE_CONVERSION; + + /* Don't allow collective operations if data transform operations should occur */ + if(!type_info.is_xform_noop) + local_cause |= H5D_MPIO_DATA_TRANSFORMS; + + /* Check whether these are both simple or scalar dataspaces */ + if(!((H5S_SIMPLE == H5S_GET_EXTENT_TYPE(mem_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(mem_space)) + && (H5S_SIMPLE == H5S_GET_EXTENT_TYPE(file_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(file_space)))) + local_cause |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES; + + /* Dataset storage must be contiguous or chunked */ + if(!(dset->shared->layout.type == H5D_CONTIGUOUS || + dset->shared->layout.type == H5D_CHUNKED)) + local_cause |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; + + /* check if external-file storage is used */ + if (dset->shared->dcpl_cache.efl.nused > 0) + local_cause |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; + + /* The handling of memory space is different for chunking and contiguous + * storage. For contiguous storage, mem_space and file_space won't change + * when it it is doing disk IO. For chunking storage, mem_space will + * change for different chunks. So for chunking storage, whether we can + * use collective IO will defer until each chunk IO is reached. + */ + +/* MSB /\* Don't allow collective operations if filters need to be applied *\/ */ +/* if(dset->shared->layout.type == H5D_CHUNKED && */ +/* dset->shared->dcpl_cache.pline.nused > 0) */ +/* local_cause |= H5D_MPIO_FILTERS; */ + } /* end for loop */ /* Check for independent I/O */ if(local_cause & H5D_MPIO_SET_INDEPENDENT) @@ -371,6 +397,9 @@ done: * * Purpose: MPI-IO function to read directly from app buffer to file. * + * This was referred from H5D__mpio_select_read for + * multi-dset work. + * * Return: non-negative on success, negative on failure. * * Programmer: @@ -378,17 +407,24 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__mpio_select_read(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, - hsize_t mpi_buf_count, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space) +H5D__mpio_select_read(const H5D_io_info_t *io_info, hsize_t mpi_buf_count, + const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space) { - const H5D_contig_storage_t *store_contig = &(io_info->store->contig); /* Contiguous storage info for this I/O operation */ + /* all dsets are in the same file, so just get it from the first dset */ + const H5F_t *file = io_info->dsets_info[0].dset->oloc.file; + void *rbuf = NULL; herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE + /* memory addr from a piece with lowest file addr */ + rbuf = io_info->base_maddr_r; + + /*OKAY: CAST DISCARDS CONST QUALIFIER*/ H5_CHECK_OVERFLOW(mpi_buf_count, hsize_t, size_t); - if(H5F_block_read(io_info->dset->oloc.file, H5FD_MEM_DRAW, store_contig->dset_addr, (size_t)mpi_buf_count, io_info->raw_dxpl_id, io_info->u.rbuf) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "can't finish collective parallel read") + if(H5F_block_read(file, H5FD_MEM_DRAW, io_info->store_faddr, (size_t)mpi_buf_count, + io_info->raw_dxpl_id, rbuf) < 0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "can't finish collective parallel read") done: FUNC_LEAVE_NOAPI(ret_value) @@ -400,6 +436,9 @@ done: * * Purpose: MPI-IO function to write directly from app buffer to file. * + * This was referred from H5D__mpio_select_write for + * multi-dset work. + * * Return: non-negative on success, negative on failure. * * Programmer: @@ -407,17 +446,22 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__mpio_select_write(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR_UNUSED *type_info, - hsize_t mpi_buf_count, const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space) +H5D__mpio_select_write(const H5D_io_info_t *io_info, hsize_t mpi_buf_count, + const H5S_t H5_ATTR_UNUSED *file_space, const H5S_t H5_ATTR_UNUSED *mem_space) { - const H5D_contig_storage_t *store_contig = &(io_info->store->contig); /* Contiguous storage info for this I/O operation */ + /* all dsets are in the same file, so just get it from the first dset */ + const H5F_t *file = io_info->dsets_info[0].dset->oloc.file; + const void *wbuf = NULL; herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE + /* memory addr from a piece with lowest file addr */ + wbuf = io_info->base_maddr_w; + /*OKAY: CAST DISCARDS CONST QUALIFIER*/ H5_CHECK_OVERFLOW(mpi_buf_count, hsize_t, size_t); - if(H5F_block_write(io_info->dset->oloc.file, H5FD_MEM_DRAW, store_contig->dset_addr, (size_t)mpi_buf_count, io_info->raw_dxpl_id, io_info->u.wbuf) < 0) + if(H5F_block_write(file, H5FD_MEM_DRAW, io_info->store_faddr, (size_t)mpi_buf_count, io_info->raw_dxpl_id, wbuf) < 0) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "can't finish collective parallel write") done: @@ -426,6 +470,86 @@ done: /*------------------------------------------------------------------------- + * Function: H5D__piece_io + * + * Purpose: Routine for choosing an IO option: + * a) Single collective IO defined by one MPI derived datatype + * to link through all pieces (chunks/contigs). Default. + * Note: previously there were other options, but cutoff as part of multi-dset work. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__piece_io(const hid_t file_id, const size_t count, H5D_io_info_t *io_info) +{ + H5P_genplist_t *dx_plist; /* Pointer to DXPL */ + H5FD_mpio_chunk_opt_t chunk_opt_mode; + int io_option = H5D_ONE_LINK_CHUNK_IO; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(io_info); + HDassert(io_info->using_mpi_vfd); + + /* Obtain the data transfer properties */ + if(NULL == (dx_plist = (H5P_genplist_t *)H5I_object(io_info->raw_dxpl_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") + + /* Check the optional property list on what to do with collective chunk IO. */ + if(H5P_get(dx_plist, H5D_XFER_MPIO_CHUNK_OPT_HARD_NAME, &chunk_opt_mode) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't get chunk optimization option") + if(H5FD_MPIO_CHUNK_ONE_IO == chunk_opt_mode) + io_option = H5D_ONE_LINK_CHUNK_IO; /*no opt*/ + +/* MSC - From merge.. remove probably */ +#if 0 + if(H5D__mpio_get_sum_chunk(io_info, fm, &sum_chunk) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to obtain the total chunk number of all processes"); + if((mpi_size = H5F_mpi_get_size(io_info->dset->oloc.file)) < 0) + HGOTO_ERROR(H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi size") + + /* Get the chunk optimization option */ + if(H5P_get(dx_plist, H5D_XFER_MPIO_CHUNK_OPT_NUM_NAME, &one_link_chunk_io_threshold) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't get chunk optimization option") + + /* step 1: choose an IO option */ + /* If the average number of chunk per process is greater than a threshold, we will do one link chunked IO. */ + if((unsigned)sum_chunk / mpi_size >= one_link_chunk_io_threshold) + io_option = H5D_ONE_LINK_CHUNK_IO_MORE_OPT; +#endif + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + { + htri_t check_prop; + int new_value; + + /*** Test collective chunk user-input optimization APIs. ***/ + check_prop = H5Pexist(io_info->raw_dxpl_id, H5D_XFER_COLL_CHUNK_LINK_HARD_NAME); + if(check_prop > 0) { + if(H5D_ONE_LINK_CHUNK_IO == io_option) { + new_value = 0; + if(H5Pset(io_info->raw_dxpl_id, H5D_XFER_COLL_CHUNK_LINK_HARD_NAME, &new_value) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTSET, FAIL, "unable to set property value") + } /* end if */ + } /* end if */ + } /* end block */ +#endif + + /* step 2: Go ahead to do IO.*/ + if(H5D_ONE_LINK_CHUNK_IO == io_option) { + if(H5D__all_piece_collective_io(file_id, count, io_info, dx_plist) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish linked chunk MPI-IO") + } /* end if */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__piece_io */ + + +/*------------------------------------------------------------------------- * Function: H5D__mpio_array_gatherv * * Purpose: Given an array, specified in local_array, by each processor @@ -1182,7 +1306,7 @@ if(H5DEBUG(D)) /* Sort the chunk address */ if(H5D__sort_chunk(io_info, fm, chunk_addr_info_array, sum_chunk) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to sort chunk address") - ctg_store.contig.dset_addr = chunk_addr_info_array[0].chunk_addr; + ctg_store.contig.dset_addr = chunk_addr_info_array[0].piece_addr; #ifdef H5D_DEBUG if(H5DEBUG(D)) @@ -1202,7 +1326,7 @@ if(H5DEBUG(D)) * and will be fed into the next call to H5S_mpio_space_type * where it will be freed. */ - if(H5S_mpio_space_type(chunk_addr_info_array[u].chunk_info.fspace, + if(H5S_mpio_space_type(chunk_addr_info_array[u].piece_info.fspace, type_info->src_type_size, &chunk_ftype[u], /* OUT: datatype created */ &chunk_mpi_file_counts[u], /* OUT */ @@ -1221,7 +1345,7 @@ if(H5DEBUG(D)) /* Sanity check */ if(is_permuted) HDassert(permute_map); - if(H5S_mpio_space_type(chunk_addr_info_array[u].chunk_info.mspace, + if(H5S_mpio_space_type(chunk_addr_info_array[u].piece_info.mspace, type_info->dst_type_size, &chunk_mtype[u], &chunk_mpi_mem_counts[u], &(chunk_mbt_is_derived_array[u]), @@ -1245,11 +1369,11 @@ if(H5DEBUG(D)) HDassert(!permute_map); /* Chunk address relative to the first chunk */ - chunk_addr_info_array[u].chunk_addr -= ctg_store.contig.dset_addr; + chunk_addr_info_array[u].piece_addr -= ctg_store.contig.dset_addr; /* Assign chunk address to MPI displacement */ /* (assume MPI_Aint big enough to hold it) */ - chunk_disp_array[u] = (MPI_Aint)chunk_addr_info_array[u].chunk_addr; + chunk_disp_array[u] = (MPI_Aint)chunk_addr_info_array[u].piece_addr; } /* end for */ /* Create final MPI derived datatype for the file */ @@ -2251,6 +2375,401 @@ if(H5DEBUG(D)) /*------------------------------------------------------------------------- + * Function: H5D__collective_read + * + * Purpose: Read directly from pieces (chunks/contig) in file into + * application memory using collective I/O. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, March 4, 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5D__collective_read(const hid_t file_id, const size_t count, H5D_io_info_t *io_info) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Call generic selection operation */ + if(H5D__piece_io(file_id, count, io_info) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__collective_read() */ + + +/*------------------------------------------------------------------------- + * Function: H5D__collective_write + * + * Purpose: Write directly to pieces (chunks/contig) in file into + * application memory using collective I/O. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, March 4, 2008 + * + *------------------------------------------------------------------------- + */ +herr_t +H5D__collective_write(const hid_t file_id, const size_t count, H5D_io_info_t *io_info) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Call generic selection operation */ + if(H5D__piece_io(file_id, count, io_info) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__collective_write() */ + + +/*------------------------------------------------------------------------- + * Function: H5D__all_piece_collective_io + * + * Purpose: Routine for single collective IO with one MPI derived datatype + * to link with all pieces (chunks + contig) + * + * 1. Use the piece addresses and piece info sorted in skiplist + * 2. Build up MPI derived datatype for each chunk + * 3. Build up the final MPI derived datatype + * 4. Use common collective IO routine to do MPI-IO + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__all_piece_collective_io(H5_ATTR_UNUSED const hid_t file_id, const size_t count, + H5D_io_info_t *io_info, H5P_genplist_t *dx_plist) +{ + MPI_Datatype chunk_final_mtype; /* Final memory MPI datatype for all chunks with seletion */ + hbool_t chunk_final_mtype_is_derived = FALSE; + MPI_Datatype chunk_final_ftype; /* Final file MPI datatype for all chunks with seletion */ + hbool_t chunk_final_ftype_is_derived = FALSE; + H5D_storage_t ctg_store; /* Storage info for "fake" contiguous dataset */ + size_t i; + MPI_Datatype *chunk_mtype = NULL; + MPI_Datatype *chunk_ftype = NULL; + MPI_Aint *chunk_file_disp_array = NULL; + MPI_Aint *chunk_mem_disp_array = NULL; + hbool_t *chunk_mft_is_derived_array = NULL; /* Flags to indicate each chunk's MPI file datatype is derived */ + hbool_t *chunk_mbt_is_derived_array = NULL; /* Flags to indicate each chunk's MPI memory datatype is derived */ + int *chunk_mpi_file_counts = NULL; /* Count of MPI file datatype for each chunk */ + int *chunk_mpi_mem_counts = NULL; /* Count of MPI memory datatype for each chunk */ + int mpi_code; /* MPI return code */ + H5D_mpio_actual_chunk_opt_mode_t actual_chunk_opt_mode = H5D_MPIO_LINK_CHUNK; + H5D_mpio_actual_io_mode_t actual_io_mode = 0; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* set actual_io_mode */ + for (i=0; i < count; i++) { + if (io_info->dsets_info[i].layout->type == H5D_CHUNKED) + actual_io_mode |= H5D_MPIO_CHUNK_COLLECTIVE; + else if (io_info->dsets_info[i].layout->type == H5D_CONTIGUOUS) { + actual_io_mode |= H5D_MPIO_CONTIGUOUS_COLLECTIVE; + + /* if only single-dset */ + if (1 == count) + actual_chunk_opt_mode = H5D_MPIO_NO_CHUNK_OPTIMIZATION; + } + else + HGOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, "unsupported storage layout") + } + + /* Set the actual-chunk-opt-mode property. */ + if(H5P_set(dx_plist, H5D_MPIO_ACTUAL_CHUNK_OPT_MODE_NAME, &actual_chunk_opt_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set actual chunk opt mode property") + + /* Set the actual-io-mode property. + * Link chunk I/O does not break to independent, so can set right away */ + if(H5P_set(dx_plist, H5D_MPIO_ACTUAL_IO_MODE_NAME, &actual_io_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "couldn't set actual io mode property") + + /* Code block for actual actions (Build a MPI Type, IO) */ + { + hsize_t mpi_buf_count; /* Number of MPI types */ + size_t num_chunk; /* Number of chunks for this process */ + size_t u=0; /* Local index variable */ + + H5SL_node_t *piece_node; /* Current node in chunk skip list */ + H5D_chunk_info_t *piece_info; + + /* local variable for base address for write buffer */ + const void * base_wbuf_addr = NULL; + void * base_rbuf_addr = NULL; + + /* Get the number of chunks with a selection */ + num_chunk = H5SL_count(io_info->sel_pieces); + H5_CHECK_OVERFLOW(num_chunk, size_t, int); + + /* Set up MPI datatype for chunks selected */ + if(num_chunk) { + /* Allocate chunking information */ + if(NULL == (chunk_mtype = (MPI_Datatype *)H5MM_malloc(num_chunk * sizeof(MPI_Datatype)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk memory datatype buffer") + if(NULL == (chunk_ftype = (MPI_Datatype *)H5MM_malloc(num_chunk * sizeof(MPI_Datatype)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file datatype buffer") + if(NULL == (chunk_file_disp_array = (MPI_Aint *)H5MM_malloc(num_chunk * sizeof(MPI_Aint)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file displacement buffer") + if(NULL == (chunk_mem_disp_array = (MPI_Aint *)H5MM_calloc(num_chunk * sizeof(MPI_Aint)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk memory displacement buffer") + if(NULL == (chunk_mpi_mem_counts = (int *)H5MM_calloc(num_chunk * sizeof(int)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk memory counts buffer") + if(NULL == (chunk_mpi_file_counts = (int *)H5MM_calloc(num_chunk * sizeof(int)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file counts buffer") + if(NULL == (chunk_mbt_is_derived_array = (hbool_t *)H5MM_calloc(num_chunk * sizeof(hbool_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk memory is derived datatype flags buffer") + if(NULL == (chunk_mft_is_derived_array = (hbool_t *)H5MM_calloc(num_chunk * sizeof(hbool_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate chunk file is derived datatype flags buffer") + + /* get first piece, which is sorted in skiplist */ + if(NULL == (piece_node = H5SL_first(io_info->sel_pieces))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get piece node from skipped list") + if(NULL == (piece_info = (H5D_chunk_info_t *)H5SL_item(piece_node))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get piece info from skipped list") + /* save lowest file address */ + ctg_store.contig.dset_addr = piece_info->faddr; + + /* save base mem addr of piece for read/write */ + base_wbuf_addr = piece_info->dset_info->u.wbuf; + base_rbuf_addr = piece_info->dset_info->u.rbuf; + +#ifdef H5D_DEBUG + if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"before iterate over selected pieces\n"); +#endif + + /* Obtain MPI derived datatype from all individual pieces */ + /* Iterate over selected pieces for this process */ + while(piece_node) { + hsize_t *permute_map = NULL; /* array that holds the mapping from the old, + out-of-order displacements to the in-order + displacements of the MPI datatypes of the + point selection of the file space */ + hbool_t is_permuted = FALSE; + + if(NULL == (piece_info = (H5D_chunk_info_t *)H5SL_item(piece_node))) + HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL,"couldn't get piece info from skipped list") + + /* Obtain disk and memory MPI derived datatype */ + /* NOTE: The permute_map array can be allocated within H5S_mpio_space_type + * and will be fed into the next call to H5S_mpio_space_type + * where it will be freed. + */ + if(H5S_mpio_space_type(piece_info->fspace, + piece_info->dset_info->type_info.src_type_size, + &chunk_ftype[u], /* OUT: datatype created */ + &chunk_mpi_file_counts[u], /* OUT */ + &(chunk_mft_is_derived_array[u]), /* OUT */ + TRUE, /* this is a file space, + so permute the + datatype if the point + selections are out of + order */ + &permute_map,/* OUT: a map to indicate the + permutation of points + selected in case they + are out of order */ + &is_permuted /* OUT */) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI file type") + + /* Sanity check */ + if(is_permuted) + HDassert(permute_map); + if(H5S_mpio_space_type(piece_info->mspace, + piece_info->dset_info->type_info.dst_type_size, + &chunk_mtype[u], + &chunk_mpi_mem_counts[u], + &(chunk_mbt_is_derived_array[u]), + FALSE, /* this is a memory + space, so if the file + space is not + permuted, there is no + need to permute the + datatype if the point + selections are out of + order*/ + &permute_map, /* IN: the permutation map + generated by the + file_space selection + and applied to the + memory selection */ + &is_permuted /* IN */) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create MPI buf type") + /* Sanity check */ + if(is_permuted) + HDassert(!permute_map); + + /* Piece address relative to the first piece addr + * Assign piece address to MPI displacement + * (assume MPI_Aint big enough to hold it) */ + chunk_file_disp_array[u] = (MPI_Aint)piece_info->faddr - (MPI_Aint)ctg_store.contig.dset_addr; + + if(io_info->op_type == H5D_IO_OP_WRITE) { + chunk_mem_disp_array[u] = (MPI_Aint)piece_info->dset_info->u.wbuf - (MPI_Aint)base_wbuf_addr; + } + else if (io_info->op_type == H5D_IO_OP_READ) { + chunk_mem_disp_array[u] = (MPI_Aint)piece_info->dset_info->u.rbuf - (MPI_Aint)base_rbuf_addr; + } + + /* Advance to next piece in list */ + u++; + piece_node = H5SL_next(piece_node); + } /* end while */ + + if(MPI_SUCCESS != (mpi_code = MPI_Type_create_struct((int)num_chunk, chunk_mpi_file_counts, + chunk_file_disp_array, chunk_ftype, + &chunk_final_ftype))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct failed", mpi_code) + + if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&chunk_final_ftype))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code) + chunk_final_ftype_is_derived = TRUE; + + /* Create final MPI derived datatype for memory */ + if(MPI_SUCCESS != (mpi_code = MPI_Type_create_struct((int)num_chunk, chunk_mpi_mem_counts, + chunk_mem_disp_array, chunk_mtype, + &chunk_final_mtype))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct failed", mpi_code) + + if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&chunk_final_mtype))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code) + chunk_final_mtype_is_derived = TRUE; + + /* Free the file & memory MPI datatypes for each chunk */ + for(u = 0; u < num_chunk; u++) { + if(chunk_mbt_is_derived_array[u]) + if(MPI_SUCCESS != (mpi_code = MPI_Type_free(chunk_mtype + u))) + HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + + if(chunk_mft_is_derived_array[u]) + if(MPI_SUCCESS != (mpi_code = MPI_Type_free(chunk_ftype + u))) + HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + } /* end for */ + + /* We have a single, complicated MPI datatype for both memory & file */ + mpi_buf_count = (hsize_t)1; + } /* end if */ + else { /* no selection at all for this process */ + + /* since this process doesn't do any io, just pass a valid addr. + * at this point dset object hear address is availbe to any + * process, so just pass it. 0x0 also work fine */ + ctg_store.contig.dset_addr = 0x0; + /* or ctg_store.contig.dset_addr = io_info->dsets_info[0].dset->oloc.addr; */ + + /* just provide a valid mem address. no actual IO occur */ + base_wbuf_addr = io_info->dsets_info[0].u.wbuf; + base_rbuf_addr = io_info->dsets_info[0].u.rbuf; + + /* Set the MPI datatype to just participate */ + chunk_final_ftype = MPI_BYTE; + chunk_final_mtype = MPI_BYTE; + + mpi_buf_count = (hsize_t)0; + } /* end else */ +#ifdef H5D_DEBUG + if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"before coming to final collective IO\n"); +#endif + /* Set up the base storage address for this piece */ + io_info->store_faddr = ctg_store.contig.dset_addr; + io_info->base_maddr_w = base_wbuf_addr; + io_info->base_maddr_r = base_rbuf_addr; + + // MSB piece_info->dset_info->type_info + /* Perform final collective I/O operation */ + if(H5D__final_collective_io_md(io_info, mpi_buf_count, &chunk_final_ftype, &chunk_final_mtype) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "couldn't finish MPI-IO") + } + +done: +#ifdef H5D_DEBUG +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"before freeing memory inside H5D_link_collective_io ret_value = %d\n", ret_value); +#endif + /* Release resources */ + if(chunk_mtype) + H5MM_xfree(chunk_mtype); + if(chunk_ftype) + H5MM_xfree(chunk_ftype); + if(chunk_file_disp_array) + H5MM_xfree(chunk_file_disp_array); + if(chunk_mem_disp_array) + H5MM_xfree(chunk_mem_disp_array); + if(chunk_mpi_mem_counts) + H5MM_xfree(chunk_mpi_mem_counts); + if(chunk_mpi_file_counts) + H5MM_xfree(chunk_mpi_file_counts); + if(chunk_mbt_is_derived_array) + H5MM_xfree(chunk_mbt_is_derived_array); + if(chunk_mft_is_derived_array) + H5MM_xfree(chunk_mft_is_derived_array); + + /* Free the MPI buf and file types, if they were derived */ + if(chunk_final_mtype_is_derived && MPI_SUCCESS != (mpi_code = MPI_Type_free(&chunk_final_mtype))) + HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + if(chunk_final_ftype_is_derived && MPI_SUCCESS != (mpi_code = MPI_Type_free(&chunk_final_ftype))) + HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__all_piece_collective_io */ + + +/*------------------------------------------------------------------------- + * Function: H5D__final_collective_io_md + * + * Purpose: Routine for the common part of collective IO with different storages. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Muqun Yang + * Monday, Feb. 13th, 2006 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__final_collective_io_md(H5D_io_info_t *io_info, + hsize_t mpi_buf_count, MPI_Datatype *mpi_file_type, MPI_Datatype *mpi_buf_type) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Pass buf type, file type to the file driver. */ + if(H5FD_mpi_setup_collective(io_info->raw_dxpl_id, mpi_buf_type, mpi_file_type) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set MPI-I/O properties") + + if(io_info->op_type == H5D_IO_OP_WRITE) { + if((io_info->io_ops.single_write_md)(io_info, mpi_buf_count, NULL, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed") + } /* end if */ + else { + if((io_info->io_ops.single_read_md)(io_info, mpi_buf_count, NULL, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed") + } /* end else */ + +done: +#ifdef H5D_DEBUG +if(H5DEBUG(D)) + HDfprintf(H5DEBUG(D),"ret_value before leaving final_collective_io=%d\n",ret_value); +#endif + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__final_collective_io */ + + +/*------------------------------------------------------------------------- * Function: H5D__cmp_chunk_addr * * Purpose: Routine to compare chunk addresses @@ -2271,8 +2790,8 @@ H5D__cmp_chunk_addr(const void *chunk_addr_info1, const void *chunk_addr_info2) FUNC_ENTER_STATIC_NOERR - addr1 = ((const H5D_chunk_addr_info_t *)chunk_addr_info1)->chunk_addr; - addr2 = ((const H5D_chunk_addr_info_t *)chunk_addr_info2)->chunk_addr; + addr1 = ((const H5D_chunk_addr_info_t *)chunk_addr_info1)->piece_addr; + addr2 = ((const H5D_chunk_addr_info_t *)chunk_addr_info2)->piece_addr; FUNC_LEAVE_NOAPI(H5F_addr_cmp(addr1, addr2)) } /* end H5D__cmp_chunk_addr() */ @@ -2452,12 +2971,12 @@ if(H5DEBUG(D)) chunk_addr = total_chunk_addr_array[chunk_info->index]; /* Check if chunk addresses are not in increasing order in the file */ - if(i > 0 && chunk_addr < chunk_addr_info_array[i - 1].chunk_addr) + if(i > 0 && chunk_addr < chunk_addr_info_array[i - 1].piece_addr) do_sort = TRUE; /* Set the address & info for this chunk */ - chunk_addr_info_array[i].chunk_addr = chunk_addr; - chunk_addr_info_array[i].chunk_info = *chunk_info; + chunk_addr_info_array[i].piece_addr = chunk_addr; + chunk_addr_info_array[i].piece_info = *chunk_info; /* Advance to next chunk in list */ i++; @@ -3402,5 +3921,89 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__filtered_collective_chunk_entry_io() */ -#endif /* H5_HAVE_PARALLEL */ + +/*------------------------------------------------------------------------- + * Function: H5D_match_coll_calls + * + * Purpose: For processes that are not reading/writing to a particular + * datasets through the multi-dataset interface, but are participating + * in the collective call, match the collective I/O calls from the + * other processes. + * + * Return: non-negative on success, negative on failure. + * + *------------------------------------------------------------------------- + */ +herr_t +H5D__match_coll_calls(hid_t file_id, H5P_genplist_t *plist, hbool_t do_read) +{ + int local_cause = 0; + int global_cause = 0; + int mpi_code; + H5F_t *file; + H5FD_mpio_collective_opt_t para_io_mode; + H5FD_mpio_xfer_t xfer_mode; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE + + HDassert(file_id > 0); + + /* Get the transfer mode */ + if(H5P_get(plist, H5D_XFER_IO_XFER_MODE_NAME, &xfer_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to get value") + HDassert(xfer_mode == H5FD_MPIO_COLLECTIVE); + + /* get parallel io mode */ + if(H5P_get(plist, H5D_XFER_MPIO_COLLECTIVE_OPT_NAME, ¶_io_mode) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "unable to get value") + + if(NULL == (file = (H5F_t *)H5I_object_verify(file_id, H5I_FILE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file") + + /* just to match up with MPI_Allreduce from H5D__mpio_opt_possible() */ + if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&local_cause, &global_cause, 1, + MPI_INT, MPI_BOR, H5F_mpi_get_comm(file)))) + HMPI_GOTO_ERROR(FAIL, "MPI_Allreduce failed", mpi_code) + + /* if collective mode is not broken according to the + * H5D__mpio_opt_possible, since the below MPI funcs will be + * called only in collective mode */ + if(!global_cause) { + MPI_Status mpi_stat; + MPI_File mpi_fh_p; + MPI_File mpi_fh; + + if(H5F_get_mpi_handle(file, (MPI_File **)&mpi_fh_p) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get mpi file handle") + mpi_fh = *(MPI_File*)mpi_fh_p; + + /* just to match up with the 1st MPI_File_set_view from H5FD_mpio_read() */ + if(MPI_SUCCESS != (mpi_code = MPI_File_set_view(mpi_fh, (MPI_Offset)0, MPI_BYTE, + MPI_BYTE, "native", MPI_INFO_NULL))) + HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code) + + /* just to match up with MPI_File_write_at_all from H5FD_mpio_read() */ + if(para_io_mode == H5FD_MPIO_COLLECTIVE_IO) { + HDmemset(&mpi_stat, 0, sizeof(MPI_Status)); + if(do_read) { + if(MPI_SUCCESS != (mpi_code = MPI_File_read_at_all(mpi_fh, 0, NULL, 0, MPI_BYTE, &mpi_stat))) + HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at_all failed", mpi_code) + } + else { + if(MPI_SUCCESS != (mpi_code = MPI_File_write_at_all(mpi_fh, 0, NULL, 0, MPI_BYTE, &mpi_stat))) + HMPI_GOTO_ERROR(FAIL, "MPI_File_write_at_all failed", mpi_code) + } + } /* end if */ + + /* just to match up with the 2nd MPI_File_set_view (reset) in H5FD_mpio_read() */ + if(MPI_SUCCESS != (mpi_code = MPI_File_set_view(mpi_fh, (MPI_Offset)0, MPI_BYTE, MPI_BYTE, + "native", MPI_INFO_NULL))) + HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code) + } /* end if !global_cause */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5FD_match_coll_calls */ +#endif /* H5_HAVE_PARALLEL */ diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index 097fab7..64075c3 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -118,6 +118,7 @@ typedef struct H5D_type_info_t { /* Forward declaration of structs used below */ struct H5D_io_info_t; +struct H5D_dset_info_t; struct H5D_chunk_map_t; /* Function pointers for I/O on particular types of dataset layouts */ @@ -125,16 +126,20 @@ typedef herr_t (*H5D_layout_construct_func_t)(H5F_t *f, H5D_t *dset); typedef herr_t (*H5D_layout_init_func_t)(H5F_t *f, hid_t dxpl_id, const H5D_t *dset, hid_t dapl_id); typedef hbool_t (*H5D_layout_is_space_alloc_func_t)(const H5O_storage_t *storage); -typedef herr_t (*H5D_layout_io_init_func_t)(const struct H5D_io_info_t *io_info, +typedef herr_t (*H5D_layout_io_init_func_t)(struct H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - struct H5D_chunk_map_t *cm); + struct H5D_dset_info_t *dinfo); typedef herr_t (*H5D_layout_read_func_t)(struct H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, - const H5S_t *mem_space, struct H5D_chunk_map_t *fm); + const H5S_t *mem_space, struct H5D_dset_info_t *dinfo); typedef herr_t (*H5D_layout_write_func_t)(struct H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, - const H5S_t *mem_space, struct H5D_chunk_map_t *fm); + const H5S_t *mem_space, struct H5D_dset_info_t *dinfo); +typedef herr_t (*H5D_layout_read_md_func_t)(const hid_t file_id, const size_t count, + struct H5D_io_info_t *io_info); +typedef herr_t (*H5D_layout_write_md_func_t)(const hid_t file_id, const size_t count, + struct H5D_io_info_t *io_info); typedef ssize_t (*H5D_layout_readvv_func_t)(const struct H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); @@ -142,7 +147,7 @@ typedef ssize_t (*H5D_layout_writevv_func_t)(const struct H5D_io_info_t *io_info size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); typedef herr_t (*H5D_layout_flush_func_t)(H5D_t *dataset, hid_t dxpl_id); -typedef herr_t (*H5D_layout_io_term_func_t)(const struct H5D_chunk_map_t *cm); +typedef herr_t (*H5D_layout_io_term_func_t)(struct H5D_io_info_t *io_info, struct H5D_dset_info_t *di); typedef herr_t (*H5D_layout_dest_func_t)(H5D_t *dataset, hid_t dxpl_id); /* Typedef for grouping layout I/O routines */ @@ -154,13 +159,13 @@ typedef struct H5D_layout_ops_t { H5D_layout_read_func_t ser_read; /* High-level I/O routine for reading data in serial */ H5D_layout_write_func_t ser_write; /* High-level I/O routine for writing data in serial */ #ifdef H5_HAVE_PARALLEL - H5D_layout_read_func_t par_read; /* High-level I/O routine for reading data in parallel */ - H5D_layout_write_func_t par_write; /* High-level I/O routine for writing data in parallel */ + H5D_layout_read_md_func_t par_read; /* High-level I/O routine for reading data in parallel */ + H5D_layout_write_md_func_t par_write; /* High-level I/O routine for writing data in parallel */ #endif /* H5_HAVE_PARALLEL */ H5D_layout_readvv_func_t readvv; /* Low-level I/O routine for reading data */ H5D_layout_writevv_func_t writevv; /* Low-level I/O routine for writing data */ H5D_layout_flush_func_t flush; /* Low-level I/O routine for flushing raw data */ - H5D_layout_io_term_func_t io_term; /* I/O shutdown routine */ + H5D_layout_io_term_func_t io_term; /* I/O shutdown routine for multi-dset */ H5D_layout_dest_func_t dest; /* Destroy layout info */ } H5D_layout_ops_t; @@ -172,12 +177,21 @@ typedef herr_t (*H5D_io_single_write_func_t)(const struct H5D_io_info_t *io_info const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space); +typedef herr_t (*H5D_io_single_read_md_func_t)(const struct H5D_io_info_t *io_info, hsize_t nelmts, + const H5S_t *file_space, const H5S_t *mem_space); +typedef herr_t (*H5D_io_single_write_md_func_t)(const struct H5D_io_info_t *io_info, hsize_t nelmts, + const H5S_t *file_space, const H5S_t *mem_space); + /* Typedef for raw data I/O framework info */ typedef struct H5D_io_ops_t { H5D_layout_read_func_t multi_read; /* High-level I/O routine for reading data */ H5D_layout_write_func_t multi_write; /* High-level I/O routine for writing data */ H5D_io_single_read_func_t single_read; /* I/O routine for reading single block */ H5D_io_single_write_func_t single_write; /* I/O routine for writing single block */ + H5D_layout_read_md_func_t multi_read_md; /* High-level I/O routine for reading data for multi-dset */ + H5D_layout_write_md_func_t multi_write_md; /* High-level I/O routine for writing data for multi-dset */ + H5D_io_single_read_md_func_t single_read_md; /* I/O routine for reading single block for multi-dset */ + H5D_io_single_write_md_func_t single_write_md; /* I/O routine for writing single block for multi-dset */ } H5D_io_ops_t; /* Typedefs for dataset storage information */ @@ -208,8 +222,99 @@ typedef enum H5D_io_op_type_t { H5D_IO_OP_WRITE /* Write operation */ } H5D_io_op_type_t; +/* piece info for multiple dsets. */ +typedef struct H5D_chunk_info_t { + haddr_t faddr; /* file addr. key of skip list */ + hsize_t index; /* "Index" of chunk in dataset */ + uint32_t piece_points; /* Number of elements selected in piece */ + hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Scaled coordinates of chunk (in file dataset's dataspace) */ + const H5S_t *fspace; /* Dataspace describing chunk & selection in it */ + unsigned fspace_shared; /* Indicate that the file space for a chunk is shared and shouldn't be freed */ + const H5S_t *mspace; /* Dataspace describing selection in memory corresponding to this chunk */ + unsigned mspace_shared; /* Indicate that the memory space for a chunk is shared and shouldn't be freed */ + struct H5D_dset_info_t *dset_info; /* Pointer to dset_info */ +} H5D_chunk_info_t; + +/* Main structure holding the mapping between file chunks and memory */ +typedef struct H5D_chunk_map_t { + H5O_layout_t *layout; /* Dataset layout information*/ + hsize_t nelmts; /* Number of elements selected in file & memory dataspaces */ + + const H5S_t *file_space; /* Pointer to the file dataspace */ + unsigned f_ndims; /* Number of dimensions for file dataspace */ + + const H5S_t *mem_space; /* Pointer to the memory dataspace */ + H5S_t *mchunk_tmpl; /* Dataspace template for new memory chunks */ + H5S_sel_iter_t mem_iter; /* Iterator for elements in memory selection */ + unsigned m_ndims; /* Number of dimensions for memory dataspace */ + H5S_sel_type msel_type; /* Selection type in memory */ + H5S_sel_type fsel_type; /* Selection type in file */ + + H5SL_t *sel_chunks; /* Skip list containing information for each chunk selected */ + + H5S_t *single_space; /* Dataspace for single chunk */ + H5D_chunk_info_t *single_chunk_info; /* Pointer to single chunk's info */ + hbool_t use_single; /* Whether I/O is on a single element */ + + hsize_t last_index; /* Index of last chunk operated on */ + H5D_chunk_info_t *last_chunk_info; /* Pointer to last chunk's info */ + + hsize_t chunk_dim[H5O_LAYOUT_NDIMS]; /* Size of chunk in each dimension */ + +#ifdef H5_HAVE_PARALLEL + H5D_chunk_info_t **select_chunk; /* Store the information about whether this chunk is selected or not */ +#endif /* H5_HAVE_PARALLEL */ +} H5D_chunk_map_t; + +/* Union for read/write dataset buffers */ +typedef union H5D_dset_buf_t { + void *rbuf; /* Pointer to buffer for read */ + const void *wbuf; /* Pointer to buffer to write */ +} H5D_dset_buf_t; + +/* dset info for multiple dsets */ +typedef struct H5D_dset_info_t { + H5D_t *dset; /* Pointer to dataset being operated on */ + H5D_storage_t *store; /* Dataset storage info */ + H5D_layout_ops_t layout_ops; /* Dataset layout I/O operation function pointers */ + H5D_dset_buf_t u; /* Buffer pointer */ + + H5O_layout_t *layout; /* Dataset layout information*/ + hsize_t nelmts; /* Number of elements selected in file & memory dataspaces */ + + const H5S_t *file_space; /* Pointer to the file dataspace */ + unsigned f_ndims; /* Number of dimensions for file dataspace */ + hsize_t f_dims[H5O_LAYOUT_NDIMS]; /* File dataspace dimensions */ + + const H5S_t *mem_space; /* Pointer to the memory dataspace */ + H5S_t *mchunk_tmpl; /* Dataspace template for new memory chunks */ + H5S_sel_iter_t mem_iter; /* Iterator for elements in memory selection */ + unsigned m_ndims; /* Number of dimensions for memory dataspace */ + H5S_sel_type msel_type; /* Selection type in memory */ + H5S_sel_type fsel_type; /* Selection type in file */ + + H5SL_t *dset_sel_pieces; /* Skiplist of selected pieces in this dataset, indexed by index */ + + H5S_t *single_space; /* Dataspace for single chunk */ + H5D_chunk_info_t *single_chunk_info; + hbool_t use_single; /* Whether I/O is on a single element */ + + hsize_t last_index; /* Index of last chunk operated on */ + H5D_chunk_info_t *last_piece_info; /* Pointer to last piece's info */ + + hsize_t chunk_dim[H5O_LAYOUT_NDIMS]; /* Size of chunk in each dimension */ + + hid_t mem_type_id; /* memory datatype ID */ + H5D_type_info_t type_info; + hbool_t type_info_init; + +#ifdef H5_HAVE_PARALLEL + H5D_chunk_info_t **select_chunk; /* Store the information about whether this chunk is selected or not */ +#endif /* H5_HAVE_PARALLEL */ + +} H5D_dset_info_t; + typedef struct H5D_io_info_t { - const H5D_t *dset; /* Pointer to dataset being operated on */ #ifndef H5_HAVE_PARALLEL const #endif /* H5_HAVE_PARALLEL */ @@ -233,8 +338,24 @@ typedef struct H5D_io_info_t { void *rbuf; /* Pointer to buffer for read */ const void *wbuf; /* Pointer to buffer to write */ } u; + + H5D_t *dset; /* Pointer to dataset being operated on */ + H5D_dset_info_t *dsets_info; /* dsets info where I/O is done to/from */ + H5SL_t *sel_pieces; /* Skip list containing information for each piece selected */ + + haddr_t store_faddr; /* lowest file addr for read/write */ + const void * base_maddr_w; /* start mem addr for write */ + void * base_maddr_r; /* start mem addr for read */ + + hbool_t is_coll_broken; /* is collective mode broken? */ } H5D_io_info_t; +/* created to pass both at once for callback func */ +typedef struct H5D_io_info_wrap_t { + H5D_io_info_t *io_info; + H5D_dset_info_t *dinfo; +} H5D_io_info_wrap_t; + /******************/ /* Chunk typedefs */ @@ -341,48 +462,6 @@ typedef struct H5D_chunk_ops_t { H5D_chunk_dest_func_t dest; /* Routine to destroy indexing information in memory */ } H5D_chunk_ops_t; -/* Structure holding information about a chunk's selection for mapping */ -typedef struct H5D_chunk_info_t { - hsize_t index; /* "Index" of chunk in dataset */ - uint32_t chunk_points; /* Number of elements selected in chunk */ - hsize_t scaled[H5O_LAYOUT_NDIMS]; /* Scaled coordinates of chunk (in file dataset's dataspace) */ - H5S_t *fspace; /* Dataspace describing chunk & selection in it */ - hbool_t fspace_shared; /* Indicate that the file space for a chunk is shared and shouldn't be freed */ - H5S_t *mspace; /* Dataspace describing selection in memory corresponding to this chunk */ - hbool_t mspace_shared; /* Indicate that the memory space for a chunk is shared and shouldn't be freed */ -} H5D_chunk_info_t; - -/* Main structure holding the mapping between file chunks and memory */ -typedef struct H5D_chunk_map_t { - H5O_layout_t *layout; /* Dataset layout information*/ - hsize_t nelmts; /* Number of elements selected in file & memory dataspaces */ - - const H5S_t *file_space; /* Pointer to the file dataspace */ - unsigned f_ndims; /* Number of dimensions for file dataspace */ - - const H5S_t *mem_space; /* Pointer to the memory dataspace */ - H5S_t *mchunk_tmpl; /* Dataspace template for new memory chunks */ - H5S_sel_iter_t mem_iter; /* Iterator for elements in memory selection */ - unsigned m_ndims; /* Number of dimensions for memory dataspace */ - H5S_sel_type msel_type; /* Selection type in memory */ - H5S_sel_type fsel_type; /* Selection type in file */ - - H5SL_t *sel_chunks; /* Skip list containing information for each chunk selected */ - - H5S_t *single_space; /* Dataspace for single chunk */ - H5D_chunk_info_t *single_chunk_info; /* Pointer to single chunk's info */ - hbool_t use_single; /* Whether I/O is on a single element */ - - hsize_t last_index; /* Index of last chunk operated on */ - H5D_chunk_info_t *last_chunk_info; /* Pointer to last chunk's info */ - - hsize_t chunk_dim[H5O_LAYOUT_NDIMS]; /* Size of chunk in each dimension */ - -#ifdef H5_HAVE_PARALLEL - H5D_chunk_info_t **select_chunk; /* Store the information about whether this chunk is selected or not */ -#endif /* H5_HAVE_PARALLEL */ -} H5D_chunk_map_t; - /* Cached information about a particular chunk */ typedef struct H5D_chunk_cached_t { hbool_t valid; /*whether cache info is valid*/ @@ -424,7 +503,7 @@ typedef struct H5D_rdcc_t { struct H5D_rdcc_ent_t **slot; /* Chunk slots, each points to a chunk*/ H5SL_t *sel_chunks; /* Skip list containing information for each chunk selected */ H5S_t *single_space; /* Dataspace for single element I/O on chunks */ - H5D_chunk_info_t *single_chunk_info; /* Pointer to single chunk's info */ + H5D_chunk_info_t *single_chunk_info; /* Pointer to single piece's info */ /* Cached information about scaled dataspace dimensions */ hsize_t scaled_dims[H5S_MAX_RANK]; /* The scaled dim sizes */ @@ -472,6 +551,7 @@ typedef struct H5D_shared_t { * dataset in certain circumstances) */ H5D_rdcc_t chunk; /* Information about chunked data */ + H5SL_t *sel_pieces; /* Skip list containing information for each piece selected */ } cache; H5D_append_flush_t append_flush; /* Append flush property information */ @@ -597,13 +677,11 @@ H5_DLL herr_t H5D_set_io_info_dxpls(H5D_io_info_t *io_info, hid_t dxpl_id); /* To convert a dataset's chunk indexing type to v1 B-tree */ H5_DLL herr_t H5D__format_convert(H5D_t *dataset, hid_t dxpl_id); -/* Internal I/O routines */ -H5_DLL herr_t H5D__read(H5D_t *dataset, hid_t mem_type_id, - const H5S_t *mem_space, const H5S_t *file_space, hid_t dset_xfer_plist, - void *buf/*out*/); -H5_DLL herr_t H5D__write(H5D_t *dataset, hid_t mem_type_id, - const H5S_t *mem_space, const H5S_t *file_space, hid_t dset_xfer_plist, - const void *buf); +/* Functions to do I/O */ +H5_DLL herr_t H5D__read(hid_t file_id, hid_t dxpl_id, size_t count, + H5D_dset_info_t *dset_info); +H5_DLL herr_t H5D__write(hid_t file_id, hid_t dxpl_id, size_t count, + H5D_dset_info_t *dset_info); /* Functions that perform direct serial I/O operations */ H5_DLL herr_t H5D__select_read(const H5D_io_info_t *io_info, @@ -649,10 +727,10 @@ H5_DLL hbool_t H5D__contig_is_space_alloc(const H5O_storage_t *storage); H5_DLL herr_t H5D__contig_fill(const H5D_io_info_t *io_info); H5_DLL herr_t H5D__contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t *fm); + H5D_dset_info_t *dinfo); H5_DLL herr_t H5D__contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t *fm); + H5D_dset_info_t *dinfo); H5_DLL herr_t H5D__contig_copy(H5F_t *f_src, const H5O_storage_contig_t *storage_src, H5F_t *f_dst, H5O_storage_contig_t *storage_dst, H5T_t *src_dtype, H5O_copy_t *cpy_info, hid_t dxpl_id); @@ -660,8 +738,8 @@ H5_DLL herr_t H5D__contig_delete(H5F_t *f, hid_t dxpl_id, const H5O_storage_t *store); /* Functions that operate on chunked dataset storage */ -H5_DLL htri_t H5D__chunk_cacheable(const H5D_io_info_t *io_info, haddr_t caddr, - hbool_t write_op); +H5_DLL htri_t H5D__chunk_cacheable(const H5D_io_info_t *io_info, H5D_dset_info_t *dset_info, + haddr_t caddr, hbool_t write_op); H5_DLL herr_t H5D__chunk_create(const H5D_t *dset /*in,out*/, hid_t dxpl_id); H5_DLL herr_t H5D__chunk_set_info(const H5D_t *dset); H5_DLL hbool_t H5D__chunk_is_space_alloc(const H5O_storage_t *storage); @@ -743,40 +821,35 @@ H5_DLL herr_t H5D__fill_term(H5D_fill_buf_info_t *fb_info); #define H5Dmpio_DEBUG #endif /*H5Dmpio_DEBUG*/ #endif/*H5S_DEBUG*/ -/* MPI-IO function to read, it will select either regular or irregular read */ + +/* MPI-IO function to read multi-dsets (Chunk, Contig), it will select either + * regular or irregular read */ H5_DLL herr_t H5D__mpio_select_read(const H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space); - -/* MPI-IO function to write, it will select either regular or irregular read */ +/* MPI-IO function to write multi-dsets (Chunk, Contig), it will select either + * regular or irregular write */ H5_DLL herr_t H5D__mpio_select_write(const H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space); -/* MPI-IO functions to handle contiguous collective IO */ -H5_DLL herr_t H5D__contig_collective_read(H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, - const H5S_t *mem_space, H5D_chunk_map_t *fm); -H5_DLL herr_t H5D__contig_collective_write(H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, - const H5S_t *mem_space, H5D_chunk_map_t *fm); +/* MPI-IO functions to handle collective IO for multiple dsets (CONTIG, CHUNK) */ +H5_DLL herr_t H5D__collective_read(const hid_t file_id, const size_t count, H5D_io_info_t *io_info); +H5_DLL herr_t H5D__collective_write(const hid_t file_id, const size_t count, H5D_io_info_t *io_info); -/* MPI-IO functions to handle chunked collective IO */ -H5_DLL herr_t H5D__chunk_collective_read(H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, - const H5S_t *mem_space, H5D_chunk_map_t *fm); -H5_DLL herr_t H5D__chunk_collective_write(H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, - const H5S_t *mem_space, H5D_chunk_map_t *fm); /* MPI-IO function to check if a direct I/O transfer is possible between * memory and the file */ -H5_DLL htri_t H5D__mpio_opt_possible(const H5D_io_info_t *io_info, - const H5S_t *file_space, const H5S_t *mem_space, - const H5D_type_info_t *type_info, H5P_genplist_t *dx_plist); +H5_DLL htri_t H5D__mpio_opt_possible(const size_t count, H5D_io_info_t *io_info, + H5P_genplist_t *dx_plist); + +/* function to invoke collective I/O calls for ranks that have no I/O + on a dataset to match other ranks' collective calls */ +H5_DLL herr_t H5D__match_coll_calls(hid_t file_id, H5P_genplist_t *plist, hbool_t do_read); #endif /* H5_HAVE_PARALLEL */ +/* for both CHUNK and CONTIG dset skiplist free (sel_pieces) for layout_ops.io_term. */ +H5_DLL herr_t H5D__piece_io_term(H5D_io_info_t *io_info, H5D_dset_info_t *di); + /* Testing functions */ #ifdef H5D_TESTING H5_DLL herr_t H5D__layout_version_test(hid_t did, unsigned *version); diff --git a/src/H5Dpublic.h b/src/H5Dpublic.h index baa844a..9118d0f 100644 --- a/src/H5Dpublic.h +++ b/src/H5Dpublic.h @@ -105,6 +105,19 @@ typedef enum H5D_fill_value_t { H5D_FILL_VALUE_USER_DEFINED =2 } H5D_fill_value_t; +/* parameter sturct for multi-dset Read/Write */ +typedef struct H5D_rw_multi_t +{ + hid_t dset_id; /* dataset ID */ + hid_t dset_space_id; /* dataset selection dataspace ID */ + hid_t mem_type_id; /* memory datatype ID */ + hid_t mem_space_id; /* memory selection dataspace ID */ + union { + void *rbuf; /* pointer to read buffer */ + const void *wbuf; /* pointer to write buffer */ + } u; +} H5D_rw_multi_t; + /* Values for VDS bounds option */ typedef enum H5D_vds_view_t { H5D_VDS_ERROR = -1, diff --git a/src/H5Dscatgath.c b/src/H5Dscatgath.c index 0ae69ee..18154fd 100644 --- a/src/H5Dscatgath.c +++ b/src/H5Dscatgath.c @@ -95,6 +95,7 @@ H5D__scatter_file(const H5D_io_info_t *_io_info, const void *_buf) { H5D_io_info_t tmp_io_info; /* Temporary I/O info object */ + H5D_dset_info_t tmp_dset_info; /* Temporary I/O info object */ hsize_t *off = NULL; /* Pointer to sequence offsets */ hsize_t mem_off; /* Offset in memory */ size_t mem_curr_seq; /* "Current sequence" in memory */ @@ -117,8 +118,10 @@ H5D__scatter_file(const H5D_io_info_t *_io_info, /* Set up temporary I/O info object */ HDmemcpy(&tmp_io_info, _io_info, sizeof(*_io_info)); + HDmemcpy(&tmp_dset_info, &(_io_info->dsets_info[0]), sizeof(tmp_dset_info)); tmp_io_info.op_type = H5D_IO_OP_WRITE; - tmp_io_info.u.wbuf = _buf; + tmp_dset_info.u.wbuf = _buf; + tmp_io_info.dsets_info = &tmp_dset_info; /* Allocate the vector I/O arrays */ if(tmp_io_info.dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) @@ -142,12 +145,12 @@ H5D__scatter_file(const H5D_io_info_t *_io_info, mem_off = 0; /* Write sequence list out */ - if((*tmp_io_info.layout_ops.writevv)(&tmp_io_info, nseq, &dset_curr_seq, + if((*tmp_dset_info.layout_ops.writevv)(&tmp_io_info, nseq, &dset_curr_seq, len, off, (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") /* Update buffer */ - tmp_io_info.u.wbuf = (const uint8_t *)tmp_io_info.u.wbuf + orig_mem_len; + tmp_dset_info.u.wbuf = (const uint8_t *)tmp_dset_info.u.wbuf + orig_mem_len; /* Decrement number of elements left to process */ nelmts -= nelem; @@ -191,6 +194,7 @@ H5D__gather_file(const H5D_io_info_t *_io_info, void *_buf/*out*/) { H5D_io_info_t tmp_io_info; /* Temporary I/O info object */ + H5D_dset_info_t tmp_dset_info; /* Temporary I/O info object */ hsize_t *off = NULL; /* Pointer to sequence offsets */ hsize_t mem_off; /* Offset in memory */ size_t mem_curr_seq; /* "Current sequence" in memory */ @@ -206,8 +210,8 @@ H5D__gather_file(const H5D_io_info_t *_io_info, /* Check args */ HDassert(_io_info); - HDassert(_io_info->dset); - HDassert(_io_info->store); + HDassert(_io_info->dsets_info[0].dset); + HDassert(_io_info->dsets_info[0].store); HDassert(space); HDassert(iter); HDassert(nelmts > 0); @@ -215,8 +219,10 @@ H5D__gather_file(const H5D_io_info_t *_io_info, /* Set up temporary I/O info object */ HDmemcpy(&tmp_io_info, _io_info, sizeof(*_io_info)); + HDmemcpy(&tmp_dset_info, &(_io_info->dsets_info[0]), sizeof(tmp_dset_info)); tmp_io_info.op_type = H5D_IO_OP_READ; - tmp_io_info.u.rbuf = _buf; + tmp_dset_info.u.rbuf = _buf; + tmp_io_info.dsets_info = &tmp_dset_info; /* Allocate the vector I/O arrays */ if(tmp_io_info.dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) @@ -240,12 +246,12 @@ H5D__gather_file(const H5D_io_info_t *_io_info, mem_off = 0; /* Read sequence list in */ - if((*tmp_io_info.layout_ops.readvv)(&tmp_io_info, nseq, &dset_curr_seq, + if((*tmp_dset_info.layout_ops.readvv)(&tmp_io_info, nseq, &dset_curr_seq, len, off, (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error") /* Update buffer */ - tmp_io_info.u.rbuf = (uint8_t *)tmp_io_info.u.rbuf + orig_mem_len; + tmp_dset_info.u.rbuf = (uint8_t *)tmp_dset_info.u.rbuf + orig_mem_len; /* Decrement number of elements left to process */ nelmts -= nelem; @@ -447,7 +453,7 @@ H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space) { const H5D_dxpl_cache_t *dxpl_cache = io_info->dxpl_cache; /* Local pointer to dataset transfer info */ - void *buf = io_info->u.rbuf; /* Local pointer to application buffer */ + void *buf = io_info->dsets_info[0].u.rbuf; /* Local pointer to application buffer */ H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info*/ hbool_t mem_iter_init = FALSE; /* Memory selection iteration info has been initialized */ H5S_sel_iter_t *bkg_iter = NULL; /* Background iteration info*/ @@ -583,7 +589,7 @@ H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_in hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space) { const H5D_dxpl_cache_t *dxpl_cache = io_info->dxpl_cache; /* Local pointer to dataset transfer info */ - const void *buf = io_info->u.wbuf; /* Local pointer to application buffer */ + const void *buf = io_info->dsets_info[0].u.wbuf; /* Local pointer to application buffer */ H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info*/ hbool_t mem_iter_init = FALSE; /* Memory selection iteration info has been initialized */ H5S_sel_iter_t *bkg_iter = NULL; /* Background iteration info*/ diff --git a/src/H5Dselect.c b/src/H5Dselect.c index b4d0515..4cd0345 100644 --- a/src/H5Dselect.c +++ b/src/H5Dselect.c @@ -107,10 +107,10 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, /* Check args */ HDassert(io_info); - HDassert(io_info->dset); - HDassert(io_info->store); + HDassert(io_info->dsets_info[0].dset); + HDassert(io_info->dsets_info[0].store); HDassert(TRUE == H5P_isa_class(io_info->raw_dxpl_id, H5P_DATASET_XFER)); - HDassert(io_info->u.rbuf); + HDassert(io_info->dsets_info[0].u.rbuf); /* Allocate the vector I/O arrays */ if(io_info->dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) @@ -143,14 +143,14 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, /* Perform I/O on memory and file sequences */ if(io_info->op_type == H5D_IO_OP_READ) { - if((tmp_file_len = (*io_info->layout_ops.readvv)(io_info, + if((tmp_file_len = (*io_info->dsets_info[0].layout_ops.readvv)(io_info, file_nseq, &curr_file_seq, file_len, file_off, mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") } /* end if */ else { HDassert(io_info->op_type == H5D_IO_OP_WRITE); - if((tmp_file_len = (*io_info->layout_ops.writevv)(io_info, + if((tmp_file_len = (*io_info->dsets_info[0].layout_ops.writevv)(io_info, file_nseq, &curr_file_seq, file_len, file_off, mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") @@ -207,14 +207,14 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, /* Perform I/O on memory and file sequences */ if(io_info->op_type == H5D_IO_OP_READ) { - if((tmp_file_len = (*io_info->layout_ops.readvv)(io_info, + if((tmp_file_len = (*io_info->dsets_info[0].layout_ops.readvv)(io_info, file_nseq, &curr_file_seq, file_len, file_off, mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") } /* end if */ else { HDassert(io_info->op_type == H5D_IO_OP_WRITE); - if((tmp_file_len = (*io_info->layout_ops.writevv)(io_info, + if((tmp_file_len = (*io_info->dsets_info[0].layout_ops.writevv)(io_info, file_nseq, &curr_file_seq, file_len, file_off, mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") diff --git a/src/H5Dvirtual.c b/src/H5Dvirtual.c index 3be2353..d347e3b 100644 --- a/src/H5Dvirtual.c +++ b/src/H5Dvirtual.c @@ -76,12 +76,12 @@ /********************/ /* Layout operation callbacks */ -static herr_t H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t - *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t *fm); -static herr_t H5D__virtual_write(H5D_io_info_t *io_info, - const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, - const H5S_t *mem_space, H5D_chunk_map_t *fm); +static herr_t H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_dset_info_t *dinfo); +static herr_t H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, + hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, + H5D_dset_info_t *dinfo); static herr_t H5D__virtual_flush(H5D_t *dset, hid_t dxpl_id); /* Other functions */ @@ -99,16 +99,16 @@ static herr_t H5D__virtual_build_source_name(char *source_name, const H5O_storage_virtual_name_seg_t *parsed_name, size_t static_strlen, size_t nsubs, hsize_t blockno, char **built_name); static herr_t H5D__virtual_init_all(const H5D_t *dset, hid_t dxpl_id); -static herr_t H5D__virtual_pre_io(H5D_io_info_t *io_info, +static herr_t H5D__virtual_pre_io(H5D_dset_info_t *dset_info, H5O_storage_virtual_t *storage, const H5S_t *file_space, - const H5S_t *mem_space, hsize_t *tot_nelmts); + const H5S_t *mem_space, hsize_t *tot_nelmts, H5D_io_info_t *io_info); static herr_t H5D__virtual_post_io(H5O_storage_virtual_t *storage); -static herr_t H5D__virtual_read_one(H5D_io_info_t *io_info, +static herr_t H5D__virtual_read_one(H5D_dset_info_t *dset_info, const H5D_type_info_t *type_info, const H5S_t *file_space, - H5O_storage_virtual_srcdset_t *source_dset); -static herr_t H5D__virtual_write_one(H5D_io_info_t *io_info, + H5O_storage_virtual_srcdset_t *source_dset, hid_t dxpl_id); +static herr_t H5D__virtual_write_one(H5D_dset_info_t *dset_info, const H5D_type_info_t *type_info, const H5S_t *file_space, - H5O_storage_virtual_srcdset_t *source_dset); + H5O_storage_virtual_srcdset_t *source_dset, hid_t dxpl_id); /*********************/ @@ -2078,10 +2078,11 @@ H5D__virtual_is_space_alloc(const H5O_storage_t H5_ATTR_UNUSED *storage) *------------------------------------------------------------------------- */ static herr_t -H5D__virtual_pre_io(H5D_io_info_t *io_info, +H5D__virtual_pre_io(H5D_dset_info_t *dset_info, H5O_storage_virtual_t *storage, const H5S_t *file_space, - const H5S_t *mem_space, hsize_t *tot_nelmts) + const H5S_t *mem_space, hsize_t *tot_nelmts, H5D_io_info_t *io_info) { + const H5D_t *dset = dset_info->dset; /* Local pointer to dataset info */ hssize_t select_nelmts; /* Number of elements in selection */ hsize_t bounds_start[H5S_MAX_RANK]; /* Selection bounds start */ hsize_t bounds_end[H5S_MAX_RANK]; /* Selection bounds end */ @@ -2100,7 +2101,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, /* Initialize layout if necessary */ if(!storage->init) - if(H5D__virtual_init_all(io_info->dset, io_info->md_dxpl_id) < 0) + if(H5D__virtual_init_all(dset, io_info->md_dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize virtual layout") /* Initialize tot_nelmts */ @@ -2120,7 +2121,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, /* Get selection bounds if necessary */ if(!bounds_init) { /* Get rank of VDS */ - if((rank = H5S_GET_EXTENT_NDIMS(io_info->dset->shared->space)) < 0) + if((rank = H5S_GET_EXTENT_NDIMS(dset->shared->space)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to get number of dimensions") /* Get selection bounds */ @@ -2158,7 +2159,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, * open the source dataset to patch it */ if(storage->list[i].source_space_status != H5O_VIRTUAL_STATUS_CORRECT) { HDassert(!storage->list[i].sub_dset[j].dset); - if(H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], &storage->list[i].sub_dset[j], io_info->md_dxpl_id) < 0) + if(H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].sub_dset[j], io_info->md_dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset") } /* end if */ @@ -2186,7 +2187,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to modify size of data space") /* Get current VDS dimensions */ - if(H5S_get_simple_extent_dims(io_info->dset->shared->space, tmp_dims, NULL) < 0) + if(H5S_get_simple_extent_dims(dset->shared->space, tmp_dims, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get VDS dimensions") /* Copy virtual selection */ @@ -2230,7 +2231,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, /* Open source dataset */ if(!storage->list[i].sub_dset[j].dset) /* Try to open dataset */ - if(H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], &storage->list[i].sub_dset[j], io_info->md_dxpl_id) < 0) + if(H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].sub_dset[j], io_info->md_dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset") /* If the source dataset is not open, mark the selected @@ -2267,7 +2268,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, /* Open source dataset */ if(!storage->list[i].source_dset.dset) /* Try to open dataset */ - if(H5D__virtual_open_source_dset(io_info->dset, &storage->list[i], &storage->list[i].source_dset, io_info->md_dxpl_id) < 0) + if(H5D__virtual_open_source_dset(dset, &storage->list[i], &storage->list[i].source_dset, io_info->md_dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, "unable to open source dataset") /* If the source dataset is not open, mark the selected elements @@ -2366,10 +2367,11 @@ H5D__virtual_post_io(H5O_storage_virtual_t *storage) *------------------------------------------------------------------------- */ static herr_t -H5D__virtual_read_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - const H5S_t *file_space, H5O_storage_virtual_srcdset_t *source_dset) +H5D__virtual_read_one(H5D_dset_info_t *dset_info, const H5D_type_info_t *type_info, + const H5S_t *file_space, H5O_storage_virtual_srcdset_t *source_dset, hid_t dxpl_id) { H5S_t *projected_src_space = NULL; /* File space for selection in a single source dataset */ + H5D_dset_info_t *dinfo = NULL; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC @@ -2388,9 +2390,26 @@ H5D__virtual_read_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, if(H5S_select_project_intersection(source_dset->clipped_virtual_select, source_dset->clipped_source_select, file_space, &projected_src_space) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto source space") - /* Perform read on source dataset */ - if(H5D__read(source_dset->dset, type_info->dst_type_id, source_dset->projected_mem_space, projected_src_space, io_info->raw_dxpl_id, io_info->u.rbuf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read source dataset") + { + hid_t file_id; /* File ID for operation */ + + /* Alloc dset_info */ + if(NULL == (dinfo = (H5D_dset_info_t *)H5MM_calloc(sizeof(H5D_dset_info_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset info array buffer") + + dinfo->dset = source_dset->dset; + dinfo->mem_space = source_dset->projected_mem_space; + dinfo->file_space = projected_src_space; + dinfo->u.rbuf = dset_info->u.rbuf; + dinfo->mem_type_id = type_info->dst_type_id; + + /* Retrieve file_id */ + file_id = H5F_FILE_ID(dinfo->dset->oloc.file); + + /* Read in the point (with the custom VL memory allocator) */ + if(H5D__read(file_id, dxpl_id, 1, dinfo) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read source dataset") + } /* Close projected_src_space */ if(H5S_close(projected_src_space) < 0) @@ -2399,6 +2418,8 @@ H5D__virtual_read_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, } /* end if */ done: + if(dinfo) + H5MM_xfree(dinfo); /* Release allocated resources on failure */ if(projected_src_space) { HDassert(ret_value < 0); @@ -2425,7 +2446,7 @@ done: static herr_t H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t H5_ATTR_UNUSED *fm) + H5D_dset_info_t *dset_info) { H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */ hsize_t tot_nelmts; /* Total number of elements mapped to mem_space */ @@ -2437,22 +2458,24 @@ H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.rbuf); + HDassert(dset_info); + HDassert(dset_info->u.rbuf); HDassert(type_info); + HDassert(dset_info == io_info->dsets_info); HDassert(mem_space); HDassert(file_space); - storage = &io_info->dset->shared->layout.storage.u.virt; + storage = &(dset_info->dset->shared->layout.storage.u.virt); HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE)); #ifdef H5_HAVE_PARALLEL /* Parallel reads are not supported (yet) */ - if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)) + if(H5F_HAS_FEATURE(dset_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)) HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel reads not supported on virtual datasets") #endif /* H5_HAVE_PARALLEL */ /* Prepare for I/O operation */ - if(H5D__virtual_pre_io(io_info, storage, file_space, mem_space, &tot_nelmts) < 0) + if(H5D__virtual_pre_io(dset_info, storage, file_space, mem_space, &tot_nelmts, io_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation") /* Iterate over mappings */ @@ -2465,12 +2488,14 @@ H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Iterate over sub-source dsets */ for(j = storage->list[i].sub_dset_io_start; j < storage->list[i].sub_dset_io_end; j++) - if(H5D__virtual_read_one(io_info, type_info, file_space, &storage->list[i].sub_dset[j]) < 0) + if(H5D__virtual_read_one(dset_info, type_info, file_space, &storage->list[i].sub_dset[j], + io_info->raw_dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset") } /* end if */ else /* Read from source dataset */ - if(H5D__virtual_read_one(io_info, type_info, file_space, &storage->list[i].source_dset) < 0) + if(H5D__virtual_read_one(dset_info, type_info, file_space, &storage->list[i].source_dset, + io_info->raw_dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "unable to read source dataset") } /* end for */ @@ -2479,7 +2504,7 @@ H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, H5D_fill_value_t fill_status; /* Fill value status */ /* Check the fill value status */ - if(H5P_is_fill_value_defined(&io_info->dset->shared->dcpl_cache.fill, &fill_status) < 0) + if(H5P_is_fill_value_defined(&dset_info->dset->shared->dcpl_cache.fill, &fill_status) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't tell if fill value defined") /* Always write fill value to memory buffer unless it is undefined */ @@ -2506,7 +2531,7 @@ H5D__virtual_read(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to clip fill selection") /* Write fill values to memory buffer */ - if(H5D__fill(io_info->dset->shared->dcpl_cache.fill.buf, io_info->dset->shared->type, io_info->u.rbuf, + if(H5D__fill(dset_info->dset->shared->dcpl_cache.fill.buf, dset_info->dset->shared->type, dset_info->u.rbuf, type_info->mem_type, fill_space, io_info->md_dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "filling buf failed") @@ -2556,10 +2581,11 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__virtual_write_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, - const H5S_t *file_space, H5O_storage_virtual_srcdset_t *source_dset) +H5D__virtual_write_one(H5D_dset_info_t *dset_info, const H5D_type_info_t *type_info, + const H5S_t *file_space, H5O_storage_virtual_srcdset_t *source_dset, hid_t dxpl_id) { H5S_t *projected_src_space = NULL; /* File space for selection in a single source dataset */ + H5D_dset_info_t *dinfo = NULL; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC @@ -2580,9 +2606,26 @@ H5D__virtual_write_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, if(H5S_select_project_intersection(source_dset->virtual_select, source_dset->clipped_source_select, file_space, &projected_src_space) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto source space") - /* Perform write on source dataset */ - if(H5D__write(source_dset->dset, type_info->dst_type_id, source_dset->projected_mem_space, projected_src_space, io_info->raw_dxpl_id, io_info->u.wbuf) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "can't write to source dataset") + { + hid_t file_id; /* File ID for operation */ + + /* Alloc dset_info */ + if(NULL == (dinfo = (H5D_dset_info_t *)H5MM_calloc(sizeof(H5D_dset_info_t)))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate dset info array buffer") + + dinfo->dset = source_dset->dset; + dinfo->mem_space = source_dset->projected_mem_space; + dinfo->file_space = projected_src_space; + dinfo->u.wbuf = dset_info->u.wbuf; + dinfo->mem_type_id = type_info->dst_type_id; + + /* Retrieve file_id */ + file_id = H5F_FILE_ID(dinfo->dset->oloc.file); + + /* Read in the point (with the custom VL memory allocator) */ + if(H5D__write(file_id, dxpl_id, 1, dinfo) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "can't read source dataset") + } /* Close projected_src_space */ if(H5S_close(projected_src_space) < 0) @@ -2591,6 +2634,9 @@ H5D__virtual_write_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, } /* end if */ done: + if(dinfo) + H5MM_xfree(dinfo); + /* Release allocated resources on failure */ if(projected_src_space) { HDassert(ret_value < 0); @@ -2614,10 +2660,10 @@ done: * *------------------------------------------------------------------------- */ -static herr_t +static herr_t H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, - H5D_chunk_map_t H5_ATTR_UNUSED *fm) + H5D_dset_info_t *dset_info) { H5O_storage_virtual_t *storage; /* Convenient pointer into layout struct */ hsize_t tot_nelmts; /* Total number of elements mapped to mem_space */ @@ -2628,22 +2674,23 @@ H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Sanity check */ HDassert(io_info); - HDassert(io_info->u.wbuf); + HDassert(dset_info); + HDassert(dset_info->u.wbuf); HDassert(type_info); HDassert(mem_space); HDassert(file_space); - storage = &io_info->dset->shared->layout.storage.u.virt; + storage = &(dset_info->dset->shared->layout.storage.u.virt); HDassert((storage->view == H5D_VDS_FIRST_MISSING) || (storage->view == H5D_VDS_LAST_AVAILABLE)); #ifdef H5_HAVE_PARALLEL /* Parallel writes are not supported (yet) */ - if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)) + if(H5F_HAS_FEATURE(dset_info->dset->oloc.file, H5FD_FEAT_HAS_MPI)) HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "parallel writes not supported on virtual datasets") #endif /* H5_HAVE_PARALLEL */ /* Prepare for I/O operation */ - if(H5D__virtual_pre_io(io_info, storage, file_space, mem_space, &tot_nelmts) < 0) + if(H5D__virtual_pre_io(dset_info, storage, file_space, mem_space, &tot_nelmts, io_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "unable to prepare for I/O operation") /* Fail if there are unmapped parts of the selection as they would not be @@ -2661,12 +2708,14 @@ H5D__virtual_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Iterate over sub-source dsets */ for(j = storage->list[i].sub_dset_io_start; j < storage->list[i].sub_dset_io_end; j++) - if(H5D__virtual_write_one(io_info, type_info, file_space, &storage->list[i].sub_dset[j]) < 0) + if(H5D__virtual_write_one(dset_info, type_info, file_space, &storage->list[i].sub_dset[j], + io_info->raw_dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write to source dataset") } /* end if */ else /* Write to source dataset */ - if(H5D__virtual_write_one(io_info, type_info, file_space, &storage->list[i].source_dset) < 0) + if(H5D__virtual_write_one(dset_info, type_info, file_space, &storage->list[i].source_dset, + io_info->raw_dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "unable to write to source dataset") } /* end for */ diff --git a/src/H5FDmpio.c b/src/H5FDmpio.c index f594d8e..5f7f626 100644 --- a/src/H5FDmpio.c +++ b/src/H5FDmpio.c @@ -600,6 +600,9 @@ done: * *------------------------------------------------------------------------- */ +/* TODO: This can be removed as we decided to remove multi-chunk-opt feature. + * For now, leave it here to make 'enc_dec_plist_with_endianess' test pass. + * This can be removed after HDFFV-8281 done */ herr_t H5Pset_dxpl_mpio_chunk_opt_num(hid_t dxpl_id, unsigned num_chunk_per_proc) { @@ -645,6 +648,9 @@ done: * *------------------------------------------------------------------------- */ +/* TODO: This can be removed as we decided to remove multi-chunk-opt feature. + * For now, leave it here to make 'enc_dec_plist_with_endianess' test pass. + * This can be removed after HDFFV-8281 done */ herr_t H5Pset_dxpl_mpio_chunk_opt_ratio(hid_t dxpl_id, unsigned percent_num_proc_per_chunk) { @@ -995,7 +1001,7 @@ H5FD_mpio_open(const char *name, unsigned flags, hid_t fapl_id, if(MPI_SUCCESS != (mpi_code = MPI_File_open(comm_dup, name, mpi_amode, info_dup, &fh))) HMPI_GOTO_ERROR(NULL, "MPI_File_open failed", mpi_code) - file_opened=1; + file_opened = 1; /* Get the MPI rank of this process and the total number of processes */ if (MPI_SUCCESS != (mpi_code=MPI_Comm_rank (comm_dup, &mpi_rank))) diff --git a/src/H5Fmpi.c b/src/H5Fmpi.c index 2ce454a..6614ae9 100644 --- a/src/H5Fmpi.c +++ b/src/H5Fmpi.c @@ -84,20 +84,24 @@ * Return: Success: The size (positive) * Failure: Negative * + * Programmer: Jonathan Kim + * June 5, 2013 + * + * Modifications: *------------------------------------------------------------------------- */ herr_t H5F_get_mpi_handle(const H5F_t *f, MPI_File **f_handle) { herr_t ret_value = SUCCEED; - hid_t fapl = -1; + hid_t fapl=-1; FUNC_ENTER_NOAPI(FAIL) assert(f && f->shared); /* Dispatch to driver */ - if ((ret_value = H5FD_get_vfd_handle(f->shared->lf, fapl, (void **)f_handle)) < 0) + if ((ret_value=H5FD_get_vfd_handle(f->shared->lf, fapl, f_handle)) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get mpi file handle") done: diff --git a/src/H5trace.c b/src/H5trace.c index 930002f..44dcec0 100644 --- a/src/H5trace.c +++ b/src/H5trace.c @@ -444,10 +444,6 @@ H5_trace(const double *returning, const char *func, const char *type, ...) fprintf(out, "H5FD_MPIO_CHUNK_ONE_IO"); break; - case H5FD_MPIO_CHUNK_MULTI_IO: - fprintf(out, "H5FD_MPIO_CHUNK_MULTI_IO"); - break; - default: fprintf(out, "%ld", (long)opt); break; @@ -647,10 +643,6 @@ H5_trace(const double *returning, const char *func, const char *type, ...) fprintf(out, "H5D_MPIO_LINK_CHUNK"); break; - case H5D_MPIO_MULTI_CHUNK: - fprintf(out, "H5D_MPIO_MULTI_CHUNK"); - break; - default: fprintf(out, "%ld", (long)chunk_opt_mode); break; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8522c1d..cced9f7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -218,6 +218,7 @@ set (H5_TESTS dtypes dsets cmpd_dset + mdset filter_fail extend external diff --git a/test/CMakeTests.cmake b/test/CMakeTests.cmake index 61ac3d2..72c0c31 100644 --- a/test/CMakeTests.cmake +++ b/test/CMakeTests.cmake @@ -1078,6 +1078,7 @@ if (HDF5_TEST_VFD) dtypes dsets cmpd_dset + mdset filter_fail extend external diff --git a/test/Makefile.am b/test/Makefile.am index ba2d79b..8a4b70c 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -54,7 +54,7 @@ TEST_PROG= testhdf5 \ cache cache_api cache_image cache_tagging lheap ohdr stab gheap \ evict_on_close farray earray btree2 fheap \ pool accum hyperslab istore bittests dt_arith page_buffer \ - dtypes dsets cmpd_dset filter_fail extend external efc objcopy links unlink \ + dtypes dsets cmpd_dset mdset filter_fail extend external efc objcopy links unlink \ twriteorder big mtime fillval mount flush1 flush2 app_ref enum \ set_extent ttsafe enc_dec_plist enc_dec_plist_cross_platform\ getname vfd ntypes dangle dtransform reserved cross_read \ @@ -163,7 +163,7 @@ flush2.chkexe_: flush1.chkexe_ # specifying a file prefix or low-level driver. Changing the file # prefix or low-level driver with environment variables will influence # the temporary file name in ways that the makefile is not aware of. -CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 compact_dataset.h5 dataset.h5 dset_offset.h5 \ +CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 mdset.h5 compact_dataset.h5 dataset.h5 dset_offset.h5 \ max_compact_dataset.h5 simple.h5 set_local.h5 random_chunks.h5 \ huge_chunks.h5 chunk_cache.h5 big_chunk.h5 chunk_fast.h5 chunk_expand.h5 \ chunk_fixed.h5 copy_dcpl_newfile.h5 partial_chunks.h5 layout_extend.h5 \ diff --git a/test/enc_dec_plist.c b/test/enc_dec_plist.c index 36db2d0..8a24a10 100644 --- a/test/enc_dec_plist.c +++ b/test/enc_dec_plist.c @@ -253,8 +253,6 @@ main(void) FAIL_STACK_ERROR if((H5Pset_dxpl_mpio_collective_opt(dxpl, H5FD_MPIO_INDIVIDUAL_IO)) < 0) FAIL_STACK_ERROR - if((H5Pset_dxpl_mpio_chunk_opt(dxpl, H5FD_MPIO_CHUNK_MULTI_IO)) < 0) - FAIL_STACK_ERROR if((H5Pset_dxpl_mpio_chunk_opt_ratio(dxpl, 30)) < 0) FAIL_STACK_ERROR if((H5Pset_dxpl_mpio_chunk_opt_num(dxpl, 40)) < 0) diff --git a/test/gen_plist.c b/test/gen_plist.c index 62693bd..cd5797d 100644 --- a/test/gen_plist.c +++ b/test/gen_plist.c @@ -180,8 +180,6 @@ main(void) assert(ret > 0); if((ret = H5Pset_dxpl_mpio_collective_opt(dxpl1, H5FD_MPIO_INDIVIDUAL_IO)) < 0) assert(ret > 0); - if((ret = H5Pset_dxpl_mpio_chunk_opt(dxpl1, H5FD_MPIO_CHUNK_MULTI_IO)) < 0) - assert(ret > 0); if((ret = H5Pset_dxpl_mpio_chunk_opt_ratio(dxpl1, 30)) < 0) assert(ret > 0); if((ret = H5Pset_dxpl_mpio_chunk_opt_num(dxpl1, 40)) < 0) diff --git a/test/mdset.c b/test/mdset.c new file mode 100644 index 0000000..ee882d1 --- /dev/null +++ b/test/mdset.c @@ -0,0 +1,557 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Neil Fortner + * March 10, 2014 + * + * Purpose: Test H5Dwrite_multi() and H5Dread_multi using randomized + * parameters. Also tests H5Dwrite() and H5Dread() using a similar + * method. + */ + +#include "h5test.h" + +#define NAME_BUF_SIZE 1024 +#define MAX_DSETS 5 +#define MAX_DSET_X 10 +#define MAX_DSET_Y 10 +#define MAX_CHUNK_X 4 +#define MAX_CHUNK_Y 4 +#define MAX_HS_X 6 +#define MAX_HS_Y 6 +#define MAX_HS 3 +#define MAX_POINTS 6 +#define OPS_PER_FILE 100 +#define DSET_MAX_NAME_LEN 8 + +/* Option flags */ +#define MDSET_FLAG_CHUNK 0x01u +#define MDSET_FLAG_SHAPESAME 0x02u +#define MDSET_FLAG_MDSET 0x04u +#define MDSET_ALL_FLAGS (MDSET_FLAG_CHUNK | MDSET_FLAG_SHAPESAME \ + | MDSET_FLAG_MDSET) + +const char *FILENAME[] = { + "mdset", + "mdset1", + "mdset2", + NULL +}; + +/* Names for datasets */ +char dset_name[MAX_DSETS][DSET_MAX_NAME_LEN]; + +static int +test_mdset_location(hid_t fapl_id) +{ + hid_t file_id1, file_id2; + herr_t ret; + H5D_rw_multi_t multi_info[2]; + hsize_t dset_dims[2]; + int *buf = NULL; + char filename1[NAME_BUF_SIZE]; + char filename2[NAME_BUF_SIZE]; + + TESTING("mdset location"); + + h5_fixname(FILENAME[1], fapl_id, filename1, sizeof filename1); + h5_fixname(FILENAME[2], fapl_id, filename2, sizeof filename2); + + /* Create files */ + if((file_id1 = H5Fcreate(filename1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) + TEST_ERROR + if((file_id2 = H5Fcreate(filename2, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) + TEST_ERROR + + if(NULL == (buf = (int *)HDcalloc(2 * MAX_DSET_X * MAX_DSET_Y, sizeof(int)))) + TEST_ERROR + + /* Generate memory dataspace */ + dset_dims[0] = MAX_DSET_X; + dset_dims[1] = MAX_DSET_Y; + if((multi_info[0].dset_space_id = H5Screate_simple(2, dset_dims, NULL)) < 0) + TEST_ERROR + if((multi_info[1].dset_space_id = H5Screate_simple(2, dset_dims, NULL)) < 0) + TEST_ERROR + + multi_info[0].mem_space_id = H5S_ALL; + multi_info[1].mem_space_id = H5S_ALL; + + multi_info[0].mem_type_id = H5T_NATIVE_UINT; + multi_info[1].mem_type_id = H5T_NATIVE_UINT; + + if((multi_info[0].dset_id = H5Dcreate2(file_id1, dset_name[0], H5T_NATIVE_UINT, + multi_info[0].dset_space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + if((multi_info[1].dset_id = H5Dcreate2(file_id2, dset_name[1], H5T_NATIVE_UINT, + multi_info[1].dset_space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR + + multi_info[0].u.wbuf = buf; + multi_info[1].u.wbuf = buf + (MAX_DSET_X * MAX_DSET_Y); + + H5E_BEGIN_TRY { + ret = H5Dwrite_multi(H5P_DEFAULT, 2, multi_info); + } H5E_END_TRY + + if(ret >= 0) { + fprintf(stderr, "H5Dmulti_write with datasets in multiple files should fail.\n"); + TEST_ERROR + } + + multi_info[0].u.rbuf = buf; + multi_info[1].u.rbuf = buf + (MAX_DSET_X * MAX_DSET_Y); + + H5E_BEGIN_TRY { + ret = H5Dread_multi(H5P_DEFAULT, 2, multi_info); + } H5E_END_TRY + + if(ret >= 0) { + fprintf(stderr, "H5Dmulti_read with datasets in multiple files should fail.\n"); + TEST_ERROR + } + + H5Dclose(multi_info[0].dset_id); + H5Sclose(multi_info[0].dset_space_id); + H5Dclose(multi_info[1].dset_id); + H5Sclose(multi_info[1].dset_space_id); + H5Fclose(file_id1); + H5Fclose(file_id2); + + if(buf) + free(buf); + + PASSED(); + return 0; + +error: + if(buf) + free(buf); + return -1; +} + +/*------------------------------------------------------------------------- + * Function: test_mdset + * + * Purpose: Test randomized I/O using one or more datasets. Creates a + * file, runs OPS_PER_FILE read or write operations verifying + * that reads return the expected data, then closes the file. + * Runs the test with a new file niter times. + * + * The operations can use either hyperslab or point + * selections. Options are available for chunked or + * contiguous layout, use of multiple datasets and H5D*_multi + * calls, and use of the "shapesame" algorithm code path. To + * avoid the shapesame path when that option is not set, this + * function simply adds a dimension to the memory buffer in a + * way that the shapesame code is not designed to handle. + * + * Return: Number of errors + * + * Programmer: Neil Fortner + * Monday, March 10, 2014 + * + *------------------------------------------------------------------------- + */ +static int +test_mdset(size_t niter, unsigned flags, hid_t fapl_id) +{ + H5D_rw_multi_t multi_info[MAX_DSETS]; + size_t max_dsets; + size_t buf_size; + size_t ndsets; + hid_t file_id = - 1; + hid_t dcpl_id = -1; + hsize_t dset_dims[MAX_DSETS][3]; + hsize_t chunk_dims[2]; + hsize_t max_dims[2] = {H5S_UNLIMITED, H5S_UNLIMITED}; + unsigned *rbuf = NULL; + unsigned *rbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *erbuf = NULL; + unsigned *erbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *wbuf = NULL; + unsigned *wbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *efbuf = NULL; + unsigned *efbufi[MAX_DSETS][MAX_DSET_X]; + hbool_t do_read; + hsize_t start[3]; + hsize_t count[3]; + hsize_t points[3 * MAX_POINTS]; + char filename[NAME_BUF_SIZE]; + size_t i, j, k, l, m, n; + + TESTING("random I/O"); + + h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename); + + /* Calculate maximum number of datasets */ + max_dsets = (flags & MDSET_FLAG_MDSET) ? MAX_DSETS : 1; + + /* Calculate buffer size */ + buf_size = max_dsets * MAX_DSET_X * MAX_DSET_Y * sizeof(unsigned); + + /* Allocate buffers */ + if(NULL == (rbuf = (unsigned *)HDmalloc(buf_size))) + TEST_ERROR + if(NULL == (erbuf = (unsigned *)HDmalloc(buf_size))) + TEST_ERROR + if(NULL == (wbuf = (unsigned *)HDmalloc(buf_size))) + TEST_ERROR + if(NULL == (efbuf = (unsigned *)HDmalloc(buf_size))) + TEST_ERROR + + /* Initialize buffer indices */ + for(i = 0; i < max_dsets; i++) + for(j = 0; j < MAX_DSET_X; j++) { + rbufi[i][j] = rbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + erbufi[i][j] = erbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + wbufi[i][j] = wbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + efbufi[i][j] = efbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + } /* end for */ + + /* Initialize 3rd dimension information (for tricking library into using + * non-"shapesame" code */ + for(i = 0; i < max_dsets; i++) + dset_dims[i][2] = 1; + start[2] = 0; + count[2] = 1; + + /* Initialize multi_info */ + for(i = 0; i < max_dsets; i++) { + multi_info[i].dset_id = -1; + multi_info[i].dset_space_id = -1; + multi_info[i].mem_type_id = H5T_NATIVE_UINT; + multi_info[i].mem_space_id = -1; + } /* end for */ + + /* Generate memory dataspace */ + dset_dims[0][0] = MAX_DSET_X; + dset_dims[0][1] = MAX_DSET_Y; + if((multi_info[0].mem_space_id = H5Screate_simple((flags & MDSET_FLAG_SHAPESAME) ? 2 : 3, dset_dims[0], NULL)) < 0) + TEST_ERROR + for(i = 1; i < max_dsets; i++) + if((multi_info[i].mem_space_id = H5Scopy(multi_info[0].mem_space_id)) < 0) + TEST_ERROR + + /* Create dcpl */ + if((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR + + /* Set fill time to alloc, and alloc time to early (so we always know + * what's in the file) */ + if(H5Pset_fill_time(dcpl_id, H5D_FILL_TIME_ALLOC) < 0) + TEST_ERROR + if(H5Pset_alloc_time(dcpl_id, H5D_ALLOC_TIME_EARLY) < 0) + TEST_ERROR + + for(i = 0; i < niter; i++) { + /* Determine number of datasets */ + ndsets = (flags & MDSET_FLAG_MDSET) + ? (size_t)((size_t)HDrandom() % max_dsets) + 1 : 1; + + /* Create file */ + if((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) + TEST_ERROR + + /* Create datasets */ + for(j = 0; j < ndsets; j++) { + /* Generate file dataspace */ + dset_dims[j][0] = (hsize_t)((HDrandom() % MAX_DSET_X) + 1); + dset_dims[j][1] = (hsize_t)((HDrandom() % MAX_DSET_Y) + 1); + if((multi_info[j].dset_space_id = H5Screate_simple(2, dset_dims[j], (flags & MDSET_FLAG_CHUNK) ? max_dims : NULL)) < 0) + TEST_ERROR + + /* Generate chunk (if requested) */ + if(flags & MDSET_FLAG_CHUNK) { + chunk_dims[0] = (hsize_t)((HDrandom() % MAX_CHUNK_X) + 1); + chunk_dims[1] = (hsize_t)((HDrandom() % MAX_CHUNK_Y) + 1); + if(H5Pset_chunk(dcpl_id, 2, chunk_dims) < 0) + TEST_ERROR + } /* end if */ + + /* Create dataset */ + if((multi_info[j].dset_id = H5Dcreate2(file_id, dset_name[j], H5T_NATIVE_UINT, multi_info[j].dset_space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) + TEST_ERROR + } /* end for */ + + /* Initialize read buffer and expected read buffer */ + (void)HDmemset(rbuf, 0, buf_size); + (void)HDmemset(erbuf, 0, buf_size); + + /* Initialize write buffer */ + for(j = 0; j < max_dsets; j++) + for(k = 0; k < MAX_DSET_X; k++) + for(l = 0; l < MAX_DSET_Y; l++) + wbufi[j][k][l] = (unsigned)((j * MAX_DSET_X * MAX_DSET_Y) + (k * MAX_DSET_Y) + l); + + /* Initialize expected file buffer */ + (void)HDmemset(efbuf, 0, buf_size); + + /* Perform read/write operations */ + for(j = 0; j < OPS_PER_FILE; j++) { + /* Decide whether to read or write */ + do_read = (hbool_t)(HDrandom() % 2); + + /* Loop over datasets */ + for(k = 0; k < ndsets; k++) { + /* Reset selection */ + if(H5Sselect_none(multi_info[k].mem_space_id) < 0) + TEST_ERROR + if(H5Sselect_none(multi_info[k].dset_space_id) < 0) + TEST_ERROR + + /* Decide whether to do a hyperslab or point selection */ + if(HDrandom() % 2) { + /* Hyperslab */ + size_t nhs = (size_t)((HDrandom() % MAX_HS) + 1); /* Number of hyperslabs */ + size_t max_hs_x = (MAX_HS_X <= dset_dims[k][0]) ? MAX_HS_X : dset_dims[k][0]; /* Determine maximum hyperslab size in X */ + size_t max_hs_y = (MAX_HS_Y <= dset_dims[k][1]) ? MAX_HS_Y : dset_dims[k][1]; /* Determine maximum hyperslab size in Y */ + + for(l = 0; l < nhs; l++) { + /* Generate hyperslab */ + count[0] = (hsize_t)(((hsize_t)HDrandom() % max_hs_x) + 1); + count[1] = (hsize_t)(((hsize_t)HDrandom() % max_hs_y) + 1); + start[0] = (count[0] == dset_dims[k][0]) ? 0 + : (hsize_t)HDrandom() % (dset_dims[k][0] - count[0] + 1); + start[1] = (count[1] == dset_dims[k][1]) ? 0 + : (hsize_t)HDrandom() % (dset_dims[k][1] - count[1] + 1); + + /* Select hyperslab */ + if(H5Sselect_hyperslab(multi_info[k].mem_space_id, H5S_SELECT_OR, start, NULL, count, NULL) < 0) + TEST_ERROR + if(H5Sselect_hyperslab(multi_info[k].dset_space_id, H5S_SELECT_OR, start, NULL, count, NULL) < 0) + TEST_ERROR + + /* Update expected buffers */ + if(do_read) { + for(m = start[0]; m < (start[0] + count[0]); m++) + for(n = start[1]; n < (start[1] + count[1]); n++) + erbufi[k][m][n] = efbufi[k][m][n]; + } /* end if */ + else + for(m = start[0]; m < (start[0] + count[0]); m++) + for(n = start[1]; n < (start[1] + count[1]); n++) + efbufi[k][m][n] = wbufi[k][m][n]; + } /* end for */ + } /* end if */ + else { + /* Point selection */ + size_t npoints = (size_t)(((size_t)HDrandom() % MAX_POINTS) + 1); /* Number of points */ + + /* Generate points */ + for(l = 0; l < npoints; l++) { + points[2 * l] = (unsigned)((hsize_t)HDrandom() % dset_dims[k][0]); + points[(2 * l) + 1] = (unsigned)((hsize_t)HDrandom() % dset_dims[k][1]); + } /* end for */ + + /* Select points in file */ + if(H5Sselect_elements(multi_info[k].dset_space_id, H5S_SELECT_APPEND, npoints, points) < 0) + TEST_ERROR + + /* Update expected buffers */ + if(do_read) { + for(l = 0; l < npoints; l++) + erbufi[k][points[2 * l]][points[(2 * l) + 1]] = efbufi[k][points[2 * l]][points[(2 * l) + 1]]; + } /* end if */ + else + for(l = 0; l < npoints; l++) + efbufi[k][points[2 * l]][points[(2 * l) + 1]] = wbufi[k][points[2 * l]][points[(2 * l) + 1]]; + + /* Convert to 3D for memory selection, if not using + * "shapesame" */ + if(!(flags & MDSET_FLAG_SHAPESAME)) { + for(l = npoints - 1; l > 0; l--) { + points[(3 * l) + 2] = 0; + points[(3 * l) + 1] = points[(2 * l) + 1]; + points[3 * l] = points[2 * l]; + } /* end for */ + points[2] = 0; + } /* end if */ + + /* Select points in memory */ + if(H5Sselect_elements(multi_info[k].mem_space_id, H5S_SELECT_APPEND, npoints, points) < 0) + TEST_ERROR + } /* end else */ + } /* end for */ + + /* Perform I/O */ + if(do_read) { + if(flags & MDSET_FLAG_MDSET) { + /* Set buffers */ + for(k = 0; k < ndsets; k++) + multi_info[k].u.rbuf = rbufi[k][0]; + + /* Read datasets */ + if(H5Dread_multi(H5P_DEFAULT, ndsets, multi_info) < 0) + TEST_ERROR + } /* end if */ + else + /* Read */ + if(H5Dread(multi_info[0].dset_id, multi_info[0].mem_type_id, multi_info[0].mem_space_id, multi_info[0].dset_space_id, H5P_DEFAULT, rbuf) < 0) + TEST_ERROR + + /* Verify data */ + if(0 != memcmp(rbuf, erbuf, buf_size)) + TEST_ERROR + } /* end if */ + else { + if(flags & MDSET_FLAG_MDSET) { + /* Set buffers */ + for(k = 0; k < ndsets; k++) + multi_info[k].u.wbuf = wbufi[k][0]; + + /* Write datasets */ + if(H5Dwrite_multi(H5P_DEFAULT, ndsets, multi_info) < 0) + TEST_ERROR + } /* end if */ + else + /* Write */ + if(H5Dwrite(multi_info[0].dset_id, multi_info[0].mem_type_id, multi_info[0].mem_space_id, multi_info[0].dset_space_id, H5P_DEFAULT, wbuf) < 0) + TEST_ERROR + + /* Update wbuf */ + for(l = 0; l < max_dsets; l++) + for(m = 0; m < MAX_DSET_X; m++) + for(n = 0; n < MAX_DSET_Y; n++) + wbufi[l][m][n] += (unsigned)max_dsets * MAX_DSET_X * MAX_DSET_Y; + } /* end else */ + } /* end for */ + + /* Close */ + for(j = 0; j < ndsets; j++) { + if(H5Dclose(multi_info[j].dset_id) < 0) + TEST_ERROR + multi_info[j].dset_id = -1; + if(H5Sclose(multi_info[j].dset_space_id) < 0) + TEST_ERROR + multi_info[j].dset_space_id = -1; + } /* end for */ + if(H5Fclose(file_id) < 0) + TEST_ERROR + file_id = -1; + } /* end for */ + + /* Close */ + for(i = 0; i < max_dsets; i++) { + if(H5Sclose(multi_info[i].mem_space_id) < 0) + TEST_ERROR + multi_info[i].mem_space_id = -1; + } /* end for */ + if(H5Pclose(dcpl_id) < 0) + TEST_ERROR + dcpl_id = -1; + free(rbuf); + rbuf = NULL; + free(erbuf); + erbuf = NULL; + free(wbuf); + wbuf = NULL; + free(efbuf); + efbuf = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY { + for(i = 0; i < max_dsets; i++) { + H5Dclose(multi_info[i].dset_id); + H5Sclose(multi_info[i].mem_space_id); + H5Sclose(multi_info[i].dset_space_id); + } /* end for */ + H5Fclose(file_id); + H5Pclose(dcpl_id); + } H5E_END_TRY + if(rbuf) + free(rbuf); + if(erbuf) + free(erbuf); + if(wbuf) + free(wbuf); + if(efbuf) + free(efbuf); + + return -1; +} /* end test_mdset() */ + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Runs all tests with all combinations of configuration + * flags. + * + * Return: Success: 0 + * Failue: 1 + * + * Programmer: Neil Fortner + * Monday, March 10, 2014 + * + *------------------------------------------------------------------------- + */ +int +main(void) +{ + hid_t fapl_id; + int nerrors = 0; + unsigned i; + int ret; + + h5_reset(); + fapl_id = h5_fileaccess(); + + /* Initialize random number seed */ + HDsrandom((unsigned)HDtime(NULL)); + + /* Fill dset_name array */ + for(i = 0; i < MAX_DSETS; i++) { + if((ret = snprintf(dset_name[i], DSET_MAX_NAME_LEN, "dset%u", i)) < 0) + TEST_ERROR + if(ret >= DSET_MAX_NAME_LEN) + TEST_ERROR + } /* end for */ + + for(i = 0; i <= MDSET_ALL_FLAGS; i++) { + /* Print flag configuration */ + puts("\nConfiguration:"); + printf(" Layout: %s\n", (i & MDSET_FLAG_CHUNK) ? "Chunked" : "Contiguous"); + printf(" Shape same: %s\n", (i & MDSET_FLAG_SHAPESAME) ? "Yes" : "No"); + printf(" I/O type: %s\n", (i & MDSET_FLAG_MDSET) ? "Multi" : "Single"); + + nerrors += test_mdset(100, i, fapl_id); + } + + /* test all datasets in same container */ + nerrors += test_mdset_location(fapl_id); + + h5_cleanup(FILENAME, fapl_id); + + if(nerrors) + goto error; + puts("All multi dataset tests passed."); + + return 0; + +error: + nerrors = MAX(1, nerrors); + printf("***** %d multi dataset TEST%s FAILED! *****\n", + nerrors, 1 == nerrors ? "" : "S"); + return 1; +} /* end main() */ + diff --git a/test/testfiles/err_compat_1 b/test/testfiles/err_compat_1 index d471e13..a761552 100644 --- a/test/testfiles/err_compat_1 +++ b/test/testfiles/err_compat_1 @@ -54,6 +54,9 @@ HDF5-DIAG: Error detected in HDF5 (version (number)) thread (IDs): #001: (file name) line (number) in test_error2(): H5Dwrite shouldn't succeed major: Error API minor: Write failed - #002: (file name) line (number) in H5Dwrite(): not a dataset + #002: (file name) line (number) in H5Dwrite(): can't init dataset info + major: Invalid arguments to routine + minor: Inappropriate type + #003: (file name) line (number) in H5D__init_dset_info(): not a dataset major: Invalid arguments to routine minor: Inappropriate type diff --git a/test/testfiles/error_test_1 b/test/testfiles/error_test_1 index 0acd288..f5687f3 100644 --- a/test/testfiles/error_test_1 +++ b/test/testfiles/error_test_1 @@ -21,7 +21,10 @@ Error Test-DIAG: Error detected in Error Program (1.0) thread (IDs): Testing error API based on data I/O HDF5-DIAG: Error detected in HDF5 (version (number)) thread (IDs): - #000: (file name) line (number) in H5Dwrite(): not a dataset + #000: (file name) line (number) in H5Dwrite(): can't init dataset info + major: Invalid arguments to routine + minor: Inappropriate type + #001: (file name) line (number) in H5D__init_dset_info(): not a dataset major: Invalid arguments to routine minor: Inappropriate type Error Test-DIAG: Error detected in Error Program (1.0) thread (IDs): @@ -32,28 +35,34 @@ Error Test-DIAG: Error detected in Error Program (1.0) thread (IDs): major: Error in IO minor: Error in H5Dwrite HDF5-DIAG: Error detected in HDF5 (version (number)) thread (IDs): - #002: (file name) line (number) in H5Dwrite(): not a dataset + #002: (file name) line (number) in H5Dwrite(): can't init dataset info + major: Invalid arguments to routine + minor: Inappropriate type + #003: (file name) line (number) in H5D__init_dset_info(): not a dataset major: Invalid arguments to routine minor: Inappropriate type Testing error message during data reading when filter isn't registered HDF5-DIAG: Error detected in HDF5 (version (number)) thread (IDs): - #000: (file name) line (number) in H5Dread(): can't read data + #000: (file name) line (number) in H5Dread(): can't prepare for reading data + major: Dataset + minor: Read failed + #001: (file name) line (number) in H5D__pre_read(): can't read data major: Dataset minor: Read failed - #001: (file name) line (number) in H5D__read(): can't read data + #002: (file name) line (number) in H5D__read(): can't read data major: Dataset minor: Read failed - #002: (file name) line (number) in H5D__chunk_read(): unable to read raw data chunk + #003: (file name) line (number) in H5D__chunk_read(): unable to read raw data chunk major: Low-level I/O minor: Read failed - #003: (file name) line (number) in H5D__chunk_lock(): data pipeline read failed + #004: (file name) line (number) in H5D__chunk_lock(): data pipeline read failed major: Data filters minor: Filter operation failed - #004: (file name) line (number) in H5Z_pipeline(): required filter 'bogus' is not registered + #005: (file name) line (number) in H5Z_pipeline(): required filter 'bogus' is not registered major: Data filters minor: Read failed - #005: (file name) line (number) in H5PL_load(): required dynamically loaded plugin filter '305' is not available + #006: (file name) line (number) in H5PL_load(): required dynamically loaded plugin filter '305' is not available major: Plugin for dynamically loaded library minor: Unable to load metadata into cache diff --git a/testpar/CMakeLists.txt b/testpar/CMakeLists.txt index 0c9f70e..ab04841 100644 --- a/testpar/CMakeLists.txt +++ b/testpar/CMakeLists.txt @@ -51,6 +51,7 @@ set (H5P_TESTS t_pshutdown t_prestart t_init_term + t_pmulti_dset t_shapesame t_filters_parallel ) diff --git a/testpar/Makefile.am b/testpar/Makefile.am index 1f15830..318f566 100644 --- a/testpar/Makefile.am +++ b/testpar/Makefile.am @@ -23,7 +23,10 @@ AM_CPPFLAGS+=-I$(top_srcdir)/src -I$(top_srcdir)/test # Test programs. These are our main targets. # -TEST_PROG_PARA=t_mpi t_bigio testphdf5 t_cache t_cache_image t_pflush1 t_pflush2 t_pread t_pshutdown t_prestart t_init_term t_shapesame t_filters_parallel +TEST_PROG_PARA=t_mpi t_bigio testphdf5 t_cache t_cache_image t_pflush1 t_pflush2 t_pread t_pshutdown t_prestart \ + t_init_term t_pmulti_dset t_shapesame + +## MSB FIX t_filters_parallel check_PROGRAMS = $(TEST_PROG_PARA) @@ -40,6 +43,6 @@ LDADD = $(LIBH5TEST) $(LIBHDF5) # shutdown.h5 is from t_pshutdown # after_mpi_fin.h5 is from t_init_term # go is used for debugging. See testphdf5.c. -CHECK_CLEANFILES+=MPItest.h5 Para*.h5 CacheTestDummy.h5 shutdown.h5 after_mpi_fin.h5 go +CHECK_CLEANFILES+=MPItest.h5 Para*.h5 CacheTestDummy.h5 shutdown.h5 pmulti_dset.h5 after_mpi_fin.h5 go include $(top_srcdir)/config/conclude.am diff --git a/testpar/t_coll_chunk.c b/testpar/t_coll_chunk.c index c6fa3d4..1e69750 100644 --- a/testpar/t_coll_chunk.c +++ b/testpar/t_coll_chunk.c @@ -299,268 +299,6 @@ coll_chunk5(void) coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_HARD, POINT, HYPER, IN_ORDER); } -/*------------------------------------------------------------------------- - * Function: coll_chunk6 - * - * Purpose: Test direct request for multi-chunk-io. - * Wrapper to test the collective chunk IO for regular JOINT - * selection with at least number of 2*mpi_size chunks - * Test for direct to Multi Chunk I/O. - * - * Return: Success: 0 - * - * Failure: -1 - * - * Programmer: Unknown - * July 12th, 2004 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ - -/* ------------------------------------------------------------------------ - * Descriptions for the selection: one singular selection accross many chunks - * Two dimensions, Num of chunks = 2* mpi_size - * - * dim1 = SPACE_DIM1*mpi_size - * dim2 = SPACE_DIM2 - * chunk_dim1 = dim1 - * chunk_dim2 = dim2 - * block = 1 for all dimensions - * stride = 1 for all dimensions - * count0 = SPACE_DIM1 - * count1 = SPACE_DIM2(3) - * start0 = mpi_rank*SPACE_DIM1 - * start1 = 0 - * - * ------------------------------------------------------------------------ - */ - -void -coll_chunk6(void) -{ - const char *filename = GetTestParameters(); - - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, HYPER, HYPER, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, HYPER, POINT, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, ALL, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, POINT, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, HYPER, OUT_OF_ORDER); - - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, ALL, IN_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, POINT, IN_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, HYPER, IN_ORDER); -} - -/*------------------------------------------------------------------------- - * Function: coll_chunk7 - * - * Purpose: Wrapper to test the collective chunk IO for regular JOINT - selection with at least number of 2*mpi_size chunks - * - * Return: Success: 0 - * - * Failure: -1 - * - * Programmer: Unknown - * July 12th, 2004 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ - -/* ------------------------------------------------------------------------ - * Descriptions for the selection: one singular selection accross many chunks - * Two dimensions, Num of chunks = 2* mpi_size - * - * dim1 = SPACE_DIM1*mpi_size - * dim2 = SPACE_DIM2 - * chunk_dim1 = dim1 - * chunk_dim2 = dim2 - * block = 1 for all dimensions - * stride = 1 for all dimensions - * count0 = SPACE_DIM1 - * count1 = SPACE_DIM2(3) - * start0 = mpi_rank*SPACE_DIM1 - * start1 = 0 - * - * ------------------------------------------------------------------------ - */ - -void -coll_chunk7(void) -{ - const char *filename = GetTestParameters(); - - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, HYPER, HYPER, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, HYPER, POINT, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, ALL, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, POINT, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, HYPER, OUT_OF_ORDER); - - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, ALL, IN_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, POINT, IN_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, HYPER, IN_ORDER); -} - -/*------------------------------------------------------------------------- - * Function: coll_chunk8 - * - * Purpose: Wrapper to test the collective chunk IO for regular JOINT - selection with at least number of 2*mpi_size chunks - * - * Return: Success: 0 - * - * Failure: -1 - * - * Programmer: Unknown - * July 12th, 2004 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ - -/* ------------------------------------------------------------------------ - * Descriptions for the selection: one singular selection accross many chunks - * Two dimensions, Num of chunks = 2* mpi_size - * - * dim1 = SPACE_DIM1*mpi_size - * dim2 = SPACE_DIM2 - * chunk_dim1 = dim1 - * chunk_dim2 = dim2 - * block = 1 for all dimensions - * stride = 1 for all dimensions - * count0 = SPACE_DIM1 - * count1 = SPACE_DIM2(3) - * start0 = mpi_rank*SPACE_DIM1 - * start1 = 0 - * - * ------------------------------------------------------------------------ - */ - -void -coll_chunk8(void) -{ - const char *filename = GetTestParameters(); - - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, HYPER, HYPER, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, HYPER, POINT, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, ALL, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, POINT, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, HYPER, OUT_OF_ORDER); - - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, ALL, IN_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, POINT, IN_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, HYPER, IN_ORDER); -} - -/*------------------------------------------------------------------------- - * Function: coll_chunk9 - * - * Purpose: Wrapper to test the collective chunk IO for regular JOINT - selection with at least number of 2*mpi_size chunks - * - * Return: Success: 0 - * - * Failure: -1 - * - * Programmer: Unknown - * July 12th, 2004 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ - -/* ------------------------------------------------------------------------ - * Descriptions for the selection: one singular selection accross many chunks - * Two dimensions, Num of chunks = 2* mpi_size - * - * dim1 = SPACE_DIM1*mpi_size - * dim2 = SPACE_DIM2 - * chunk_dim1 = dim1 - * chunk_dim2 = dim2 - * block = 1 for all dimensions - * stride = 1 for all dimensions - * count0 = SPACE_DIM1 - * count1 = SPACE_DIM2(3) - * start0 = mpi_rank*SPACE_DIM1 - * start1 = 0 - * - * ------------------------------------------------------------------------ - */ - -void -coll_chunk9(void) -{ - const char *filename = GetTestParameters(); - - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, HYPER, HYPER, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, HYPER, POINT, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, ALL, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, POINT, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, HYPER, OUT_OF_ORDER); - - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, ALL, IN_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, POINT, IN_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, HYPER, IN_ORDER); -} - -/*------------------------------------------------------------------------- - * Function: coll_chunk10 - * - * Purpose: Wrapper to test the collective chunk IO for regular JOINT - selection with at least number of 2*mpi_size chunks - * - * Return: Success: 0 - * - * Failure: -1 - * - * Programmer: Unknown - * July 12th, 2004 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ - -/* ------------------------------------------------------------------------ - * Descriptions for the selection: one singular selection accross many chunks - * Two dimensions, Num of chunks = 2* mpi_size - * - * dim1 = SPACE_DIM1*mpi_size - * dim2 = SPACE_DIM2 - * chunk_dim1 = dim1 - * chunk_dim2 = dim2 - * block = 1 for all dimensions - * stride = 1 for all dimensions - * count0 = SPACE_DIM1 - * count1 = SPACE_DIM2(3) - * start0 = mpi_rank*SPACE_DIM1 - * start1 = 0 - * - * ------------------------------------------------------------------------ - */ - -void -coll_chunk10(void) -{ - const char *filename = GetTestParameters(); - - coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, HYPER, HYPER, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, HYPER, POINT, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, ALL, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, POINT, OUT_OF_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, HYPER, OUT_OF_ORDER); - - coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, ALL, IN_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, POINT, IN_ORDER); - coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, HYPER, IN_ORDER); -} - /*------------------------------------------------------------------------- * Function: coll_chunktest @@ -753,35 +491,6 @@ coll_chunktest(const char* filename, VRFY((status>= 0),"collective chunk optimization succeeded"); break; - case API_MULTI_HARD: - status = H5Pset_dxpl_mpio_chunk_opt(xfer_plist,H5FD_MPIO_CHUNK_MULTI_IO); - VRFY((status>= 0),"collective chunk optimization succeeded "); - break; - - case API_LINK_TRUE: - status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist,2); - VRFY((status>= 0),"collective chunk optimization set chunk number succeeded"); - break; - - case API_LINK_FALSE: - status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist,6); - VRFY((status>= 0),"collective chunk optimization set chunk number succeeded"); - break; - - case API_MULTI_COLL: - status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist,8);/* make sure it is using multi-chunk IO */ - VRFY((status>= 0),"collective chunk optimization set chunk number succeeded"); - status = H5Pset_dxpl_mpio_chunk_opt_ratio(xfer_plist,50); - VRFY((status>= 0),"collective chunk optimization set chunk ratio succeeded"); - break; - - case API_MULTI_IND: - status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist,8);/* make sure it is using multi-chunk IO */ - VRFY((status>= 0),"collective chunk optimization set chunk number succeeded"); - status = H5Pset_dxpl_mpio_chunk_opt_ratio(xfer_plist,100); - VRFY((status>= 0),"collective chunk optimization set chunk ratio succeeded"); - break; - default: ; } @@ -796,41 +505,6 @@ coll_chunktest(const char* filename, VRFY((status >= 0),"testing property list inserted succeeded"); break; - case API_MULTI_HARD: - prop_value = H5D_XFER_COLL_CHUNK_DEF; - status = H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME, H5D_XFER_COLL_CHUNK_SIZE, &prop_value, - NULL, NULL, NULL, NULL, NULL, NULL); - VRFY((status >= 0),"testing property list inserted succeeded"); - break; - - case API_LINK_TRUE: - prop_value = H5D_XFER_COLL_CHUNK_DEF; - status = H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME, H5D_XFER_COLL_CHUNK_SIZE, &prop_value, - NULL, NULL, NULL, NULL, NULL, NULL); - VRFY((status >= 0),"testing property list inserted succeeded"); - break; - - case API_LINK_FALSE: - prop_value = H5D_XFER_COLL_CHUNK_DEF; - status = H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME, H5D_XFER_COLL_CHUNK_SIZE, &prop_value, - NULL, NULL, NULL, NULL, NULL, NULL); - VRFY((status >= 0),"testing property list inserted succeeded"); - break; - - case API_MULTI_COLL: - prop_value = H5D_XFER_COLL_CHUNK_DEF; - status = H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME, H5D_XFER_COLL_CHUNK_SIZE, &prop_value, - NULL, NULL, NULL, NULL, NULL, NULL); - VRFY((status >= 0),"testing property list inserted succeeded"); - break; - - case API_MULTI_IND: - prop_value = H5D_XFER_COLL_CHUNK_DEF; - status = H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME, H5D_XFER_COLL_CHUNK_SIZE, &prop_value, - NULL, NULL, NULL, NULL, NULL, NULL); - VRFY((status >= 0),"testing property list inserted succeeded"); - break; - default: ; } @@ -851,36 +525,6 @@ coll_chunktest(const char* filename, VRFY((prop_value == 0),"API to set LINK COLLECTIVE IO directly succeeded"); break; - case API_MULTI_HARD: - status = H5Pget(xfer_plist,H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME,&prop_value); - VRFY((status >= 0),"testing property list get succeeded"); - VRFY((prop_value == 0),"API to set MULTI-CHUNK COLLECTIVE IO optimization succeeded"); - break; - - case API_LINK_TRUE: - status = H5Pget(xfer_plist,H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME,&prop_value); - VRFY((status >= 0),"testing property list get succeeded"); - VRFY((prop_value == 0),"API to set LINK COLLECTIVE IO succeeded"); - break; - - case API_LINK_FALSE: - status = H5Pget(xfer_plist,H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME,&prop_value); - VRFY((status >= 0),"testing property list get succeeded"); - VRFY((prop_value == 0),"API to set LINK IO transferring to multi-chunk IO succeeded"); - break; - - case API_MULTI_COLL: - status = H5Pget(xfer_plist,H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME,&prop_value); - VRFY((status >= 0),"testing property list get succeeded"); - VRFY((prop_value == 0),"API to set MULTI-CHUNK COLLECTIVE IO with optimization succeeded"); - break; - - case API_MULTI_IND: - status = H5Pget(xfer_plist,H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME,&prop_value); - VRFY((status >= 0),"testing property list get succeeded"); - VRFY((prop_value == 0),"API to set MULTI-CHUNK IO transferring to independent IO succeeded"); - break; - default: ; } diff --git a/testpar/t_dset.c b/testpar/t_dset.c index 65d1bb4..4d9d2b4 100644 --- a/testpar/t_dset.c +++ b/testpar/t_dset.c @@ -2204,10 +2204,10 @@ extend_writeAll(void) VRFY((ret>= 0),"set independent IO collectively succeeded"); } - /* write data collectively */ ret = H5Dwrite(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + H5Eprint2(H5E_DEFAULT, stderr); VRFY((ret >= 0), "H5Dwrite succeeded"); /* release resource */ @@ -2894,26 +2894,6 @@ none_selection_chunk(void) * as some dxpl flags to get collective I/O to break in different ways. * * The relevant I/O function and expected response for each mode: - * TEST_ACTUAL_IO_MULTI_CHUNK_IND: - * H5D_mpi_chunk_collective_io, each process reports independent I/O - * - * TEST_ACTUAL_IO_MULTI_CHUNK_COL: - * H5D_mpi_chunk_collective_io, each process reports collective I/O - * - * TEST_ACTUAL_IO_MULTI_CHUNK_MIX: - * H5D_mpi_chunk_collective_io, each process reports mixed I/O - * - * TEST_ACTUAL_IO_MULTI_CHUNK_MIX_DISAGREE: - * H5D_mpi_chunk_collective_io, processes disagree. The root reports - * collective, the rest report independent I/O - * - * TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_IND: - * Same test TEST_ACTUAL_IO_MULTI_CHUNK_IND. - * Set directly go to multi-chunk-io without num threshold calc. - * TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_COL: - * Same test TEST_ACTUAL_IO_MULTI_CHUNK_COL. - * Set directly go to multi-chunk-io without num threshold calc. - * * TEST_ACTUAL_IO_LINK_CHUNK: * H5D_link_chunk_collective_io, processes report linked chunk I/O * @@ -2927,9 +2907,8 @@ none_selection_chunk(void) * TEST_ACTUAL_IO_RESET: * Perfroms collective and then independent I/O wit hthe same dxpl to * make sure the peroperty is correctly reset to the default on each use. - * Specifically, this test runs TEST_ACTUAL_IO_MULTI_CHUNK_NO_OPT_MIX_DISAGREE - * (The most complex case that works on all builds) and then performs - * an independent read and write with the same dxpls. + * This test shares with TEST_ACTUAL_IO_LINK_CHUNK case + * and then performs an independent read and write with the same dxpls. * * Note: DIRECT_MULTI_CHUNK_MIX and DIRECT_MULTI_CHUNK_MIX_DISAGREE * is not needed as they are covered by DIRECT_CHUNK_MIX and @@ -2937,6 +2916,11 @@ none_selection_chunk(void) * path way to multi-chunk-io by H5FD_MPIO_CHUNK_MULTI_IO insted of num-threshold. * * Modification: + * - Work for HDFFV-8313. Removed multi-chunk-opt related cases + * - by decision to remove multi-chunk-opt feature. + * - Jonathan Kim (2013-09-19) + * + * Modification: * - Refctore to remove multi-chunk-without-opimization test and update for * testing direct to multi-chunk-io * Programmer: Jonathan Kim @@ -2956,8 +2940,6 @@ test_actual_io_mode(int selection_mode) { H5D_mpio_actual_io_mode_t actual_io_mode_expected = -1; const char * filename; const char * test_name; - hbool_t direct_multi_chunk_io; - hbool_t multi_chunk_io; hbool_t is_chunked; hbool_t is_collective; int mpi_size = -1; @@ -2986,21 +2968,6 @@ test_actual_io_mode(int selection_mode) { char message[256]; herr_t ret; - /* Set up some flags to make some future if statements slightly more readable */ - direct_multi_chunk_io = ( - selection_mode == TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_IND || - selection_mode == TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_COL ); - - /* Note: RESET performs the same tests as MULTI_CHUNK_MIX_DISAGREE and then - * tests independent I/O - */ - multi_chunk_io = ( - selection_mode == TEST_ACTUAL_IO_MULTI_CHUNK_IND || - selection_mode == TEST_ACTUAL_IO_MULTI_CHUNK_COL || - selection_mode == TEST_ACTUAL_IO_MULTI_CHUNK_MIX || - selection_mode == TEST_ACTUAL_IO_MULTI_CHUNK_MIX_DISAGREE || - selection_mode == TEST_ACTUAL_IO_RESET ); - is_chunked = ( selection_mode != TEST_ACTUAL_IO_CONTIGUOUS && selection_mode != TEST_ACTUAL_IO_NO_COLLECTIVE); @@ -3060,129 +3027,26 @@ test_actual_io_mode(int selection_mode) { /* Choose a selection method based on the type of I/O we want to occur, * and also set up some selection-dependeent test info. */ switch(selection_mode) { - - /* Independent I/O with optimization */ - case TEST_ACTUAL_IO_MULTI_CHUNK_IND: - case TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_IND: - /* Since the dataset is chunked by row and each process selects a row, - * each process writes to a different chunk. This forces all I/O to be - * independent. - */ - slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); - - test_name = "Multi Chunk - Independent"; - actual_chunk_opt_mode_expected = H5D_MPIO_MULTI_CHUNK; - actual_io_mode_expected = H5D_MPIO_CHUNK_INDEPENDENT; - break; - - /* Collective I/O with optimization */ - case TEST_ACTUAL_IO_MULTI_CHUNK_COL: - case TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_COL: - /* The dataset is chunked by rows, so each process takes a column which - * spans all chunks. Since the processes write non-overlapping regular - * selections to each chunk, the operation is purely collective. - */ - slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); - - test_name = "Multi Chunk - Collective"; - actual_chunk_opt_mode_expected = H5D_MPIO_MULTI_CHUNK; - if(mpi_size > 1) - actual_io_mode_expected = H5D_MPIO_CHUNK_COLLECTIVE; - else - actual_io_mode_expected = H5D_MPIO_CHUNK_INDEPENDENT; - break; - - /* Mixed I/O with optimization */ - case TEST_ACTUAL_IO_MULTI_CHUNK_MIX: - /* A chunk will be assigned collective I/O only if it is selected by each - * process. To get mixed I/O, have the root select all chunks and each - * subsequent process select the first and nth chunk. The first chunk, - * accessed by all, will be assigned collective I/O while each other chunk - * will be accessed only by the root and the nth procecess and will be - * assigned independent I/O. Each process will access one chunk collectively - * and at least one chunk independently, reporting mixed I/O. - */ - - if(mpi_rank == 0) { - /* Select the first column */ - slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); - } else { - /* Select the first and the nth chunk in the nth column */ - block[0] = dim0 / mpi_size; - block[1] = dim1 / mpi_size; - count[0] = 2; - count[1] = 1; - stride[0] = mpi_rank * block[0]; - stride[1] = 1; - start[0] = 0; - start[1] = mpi_rank*block[1]; - } - - test_name = "Multi Chunk - Mixed"; - actual_chunk_opt_mode_expected = H5D_MPIO_MULTI_CHUNK; - actual_io_mode_expected = H5D_MPIO_CHUNK_MIXED; - break; - - /* RESET tests that the properties are properly reset to defaults each time I/O is - * performed. To acheive this, we have RESET perform collective I/O (which would change - * the values from the defaults) followed by independent I/O (which should report the - * default values). RESET doesn't need to have a unique selection, so we reuse - * MULTI_CHUMK_MIX_DISAGREE, which was chosen because it is a complex case that works - * on all builds. The independent section of RESET can be found at the end of this function. + /* RESET tests that the properties are properly reset to defaults each + * time I/O is performed. To acheive this, we have RESET perform + * collective I/O (which would change the values from the defaults) + * followed by independent I/O (which should report the default + * values). RESET doesn't need to have a unique selection, so we just + * reuse LINK_CHUNK, The independent section of RESET can be found at + * the end of this function. */ case TEST_ACTUAL_IO_RESET: - /* Mixed I/O with optimization and internal disagreement */ - case TEST_ACTUAL_IO_MULTI_CHUNK_MIX_DISAGREE: - /* A chunk will be assigned collective I/O only if it is selected by each - * process. To get mixed I/O with disagreement, assign process n to the - * first chunk and the nth chunk. The first chunk, selected by all, is - * assgigned collective I/O, while each other process gets independent I/O. - * Since the root process with only access the first chunk, it will report - * collective I/O. The subsequent processes will access the first chunk - * collectively, and their other chunk indpendently, reporting mixed I/O. - */ - - if(mpi_rank == 0) { - /* Select the first chunk in the first column */ - slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); - block[0] = block[0] / mpi_size; - } else { - /* Select the first and the nth chunk in the nth column */ - block[0] = dim0 / mpi_size; - block[1] = dim1 / mpi_size; - count[0] = 2; - count[1] = 1; - stride[0] = mpi_rank * block[0]; - stride[1] = 1; - start[0] = 0; - start[1] = mpi_rank*block[1]; - } - - /* If the testname was not already set by the RESET case */ - if (selection_mode == TEST_ACTUAL_IO_RESET) - test_name = "RESET"; - else - test_name = "Multi Chunk - Mixed (Disagreement)"; - - actual_chunk_opt_mode_expected = H5D_MPIO_MULTI_CHUNK; - if(mpi_size > 1) { - if(mpi_rank == 0) - actual_io_mode_expected = H5D_MPIO_CHUNK_COLLECTIVE; - else - actual_io_mode_expected = H5D_MPIO_CHUNK_MIXED; - } - else - actual_io_mode_expected = H5D_MPIO_CHUNK_INDEPENDENT; - - break; - /* Linked Chunk I/O */ case TEST_ACTUAL_IO_LINK_CHUNK: /* Nothing special; link chunk I/O is forced in the dxpl settings. */ slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); - test_name = "Link Chunk"; + /* If the testname was not already set by the RESET case */ + if (selection_mode == TEST_ACTUAL_IO_RESET) + test_name = "RESET"; + else + test_name = "Link Chunk"; actual_chunk_opt_mode_expected = H5D_MPIO_LINK_CHUNK; actual_io_mode_expected = H5D_MPIO_CHUNK_COLLECTIVE; break; @@ -3243,29 +3107,6 @@ test_actual_io_mode(int selection_mode) { /* Request collective I/O */ ret = H5Pset_dxpl_mpio(dxpl_write, H5FD_MPIO_COLLECTIVE); VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); - - /* Set the threshold number of processes per chunk to twice mpi_size. - * This will prevent the threshold from ever being met, thus forcing - * multi chunk io instead of link chunk io. - * This is via deault. - */ - if(multi_chunk_io) { - /* force multi-chunk-io by threshold */ - ret = H5Pset_dxpl_mpio_chunk_opt_num(dxpl_write, (unsigned) mpi_size*2); - VRFY((ret >= 0), "H5Pset_dxpl_mpio_chunk_opt_num succeeded"); - - /* set this to manipulate testing senario about allocating processes - * to chunks */ - ret = H5Pset_dxpl_mpio_chunk_opt_ratio(dxpl_write, (unsigned) 99); - VRFY((ret >= 0), "H5Pset_dxpl_mpio_chunk_opt_ratio succeeded"); - } - - /* Set directly go to multi-chunk-io without threshold calc. */ - if(direct_multi_chunk_io) { - /* set for multi chunk io by property*/ - ret = H5Pset_dxpl_mpio_chunk_opt(dxpl_write, H5FD_MPIO_CHUNK_MULTI_IO); - VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); - } } /* Make a copy of the dxpl to test the read operation */ @@ -3315,6 +3156,9 @@ test_actual_io_mode(int selection_mode) { /* To test that the property is succesfully reset to the default, we perform some * independent I/O after the collective I/O + * For the above collective I/O actual_chunk_opt_mode for read/write was + * expected as H5D_MPIO_LINK_CHUNK, but they are expected as + * H5D_MPIO_NO_CHUNK_OPTIMIZATION for independent I/O here. */ if (selection_mode == TEST_ACTUAL_IO_RESET) { if (mpi_rank == 0) { @@ -3375,6 +3219,11 @@ test_actual_io_mode(int selection_mode) { * * Purpose: Tests all possible cases of the actual_io_mode property. * + * Modification: + * - Work base for HDFFV-8313. Removed multi-chunk-opt related cases + * - by decision to remove multi-chunk-opt feature. + * - Jonathan Kim (2013-09-19) + * * Programmer: Jacob Gruber * Date: 2011-04-06 */ @@ -3384,32 +3233,12 @@ actual_io_mode_tests(void) { int mpi_rank = -1; MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); MPI_Comm_size(MPI_COMM_WORLD, &mpi_rank); - - test_actual_io_mode(TEST_ACTUAL_IO_NO_COLLECTIVE); - - /* - * Test multi-chunk-io via proc_num threshold - */ - test_actual_io_mode(TEST_ACTUAL_IO_MULTI_CHUNK_IND); - test_actual_io_mode(TEST_ACTUAL_IO_MULTI_CHUNK_COL); - - /* The Multi Chunk Mixed test requires atleast three processes. */ - if (mpi_size > 2) - test_actual_io_mode(TEST_ACTUAL_IO_MULTI_CHUNK_MIX); - else - HDfprintf(stdout, "Multi Chunk Mixed test requires 3 proceses minimum\n"); - - test_actual_io_mode(TEST_ACTUAL_IO_MULTI_CHUNK_MIX_DISAGREE); - /* - * Test multi-chunk-io via setting direct property - */ - test_actual_io_mode(TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_IND); - test_actual_io_mode(TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_COL); + test_actual_io_mode(TEST_ACTUAL_IO_NO_COLLECTIVE); test_actual_io_mode(TEST_ACTUAL_IO_LINK_CHUNK); test_actual_io_mode(TEST_ACTUAL_IO_CONTIGUOUS); - + test_actual_io_mode(TEST_ACTUAL_IO_RESET); return; } diff --git a/testpar/t_pmulti_dset.c b/testpar/t_pmulti_dset.c new file mode 100644 index 0000000..f098ced --- /dev/null +++ b/testpar/t_pmulti_dset.c @@ -0,0 +1,651 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Neil Fortner + * March 10, 2014 + * + * Purpose: Test H5Dwrite_multi() and H5Dread_multi using randomized + * parameters in parallel. Also tests H5Dwrite() and H5Dread() + * using a similar method. + * + * Note that this test currently relies on all processes generating + * the same sequence of random numbers after using a shared seed + * value, therefore it may not work across multiple machines. + */ + +#include "h5test.h" +#include "testpar.h" + +#define T_PMD_ERROR \ + {nerrors++; H5_FAILED(); AT(); printf("seed = %u\n", seed);} + +#define FILENAME "pmulti_dset.h5" +#define MAX_DSETS 5 +#define MAX_DSET_X 15 +#define MAX_DSET_Y 10 +#define MAX_CHUNK_X 8 +#define MAX_CHUNK_Y 6 +#define MAX_HS_X 4 +#define MAX_HS_Y 2 +#define MAX_HS 2 +#define MAX_POINTS 6 +#define MAX_SEL_RETRIES 10 +#define OPS_PER_FILE 25 +#define DSET_MAX_NAME_LEN 8 + +/* Option flags */ +#define MDSET_FLAG_CHUNK 0x01u +#define MDSET_FLAG_SHAPESAME 0x02u +#define MDSET_FLAG_MDSET 0x04u +#define MDSET_FLAG_COLLECTIVE 0x08u +#define MDSET_ALL_FLAGS (MDSET_FLAG_CHUNK | MDSET_FLAG_SHAPESAME \ + | MDSET_FLAG_MDSET | MDSET_FLAG_COLLECTIVE) + +/* MPI variables */ +int mpi_size; +int mpi_rank; + +/* Names for datasets */ +char dset_name[MAX_DSETS][DSET_MAX_NAME_LEN]; + +/* Random number seed */ +unsigned seed; + +/* Number of errors */ +int nerrors = 0; + + +/*------------------------------------------------------------------------- + * Function: test_pmdset + * + * Purpose: Test randomized I/O using one or more datasets. Creates a + * file, runs OPS_PER_FILE read or write operations verifying + * that reads return the expected data, then closes the file. + * Runs the test with a new file niter times. + * + * The operations can use either hyperslab or point + * selections. Options are available for chunked or + * contiguous layout, use of multiple datasets and H5D*_multi + * calls, and use of the "shapesame" algorithm code path. To + * avoid the shapesame path when that option is not set, this + * function simply adds a dimension to the memory buffer in a + * way that the shapesame code is not designed to handle. + * + * Return: Number of errors + * + * Programmer: Neil Fortner + * Monday, March 10, 2014 + * + *------------------------------------------------------------------------- + */ +static void +test_pmdset(size_t niter, unsigned flags) +{ + H5D_rw_multi_t multi_info[MAX_DSETS]; + size_t max_dsets; + size_t buf_size; + size_t ndsets; + hid_t file_id = -1; + hid_t fapl_id = -1; + hid_t dcpl_id = -1; + hid_t dxpl_id = -1; + hsize_t dset_dims[MAX_DSETS][3]; + hsize_t chunk_dims[2]; + hsize_t max_dims[2] = {H5S_UNLIMITED, H5S_UNLIMITED}; + unsigned *rbuf = NULL; + unsigned *rbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *erbuf = NULL; + unsigned *erbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *wbuf = NULL; + unsigned *wbufi[MAX_DSETS][MAX_DSET_X]; + unsigned *efbuf = NULL; + unsigned *efbufi[MAX_DSETS][MAX_DSET_X]; + unsigned char *dset_usage; + unsigned char *dset_usagei[MAX_DSETS][MAX_DSET_X]; + hbool_t do_read; + hbool_t last_read; + hbool_t overlap; + hsize_t start[MAX_HS][3]; + hsize_t count[MAX_HS][3]; + hsize_t points[3 * MAX_POINTS]; + int rank_data_diff; + unsigned op_data_incr; + size_t i, j, k, l, m, n, o, p; + + if(mpi_rank == 0) + TESTING("random I/O"); + + /* Calculate maximum number of datasets */ + max_dsets = (flags & MDSET_FLAG_MDSET) ? MAX_DSETS : 1; + + /* Calculate data increment per write operation */ + op_data_incr = (unsigned)max_dsets * MAX_DSET_X * MAX_DSET_Y * (unsigned)mpi_size; + + /* Calculate buffer size */ + buf_size = max_dsets * MAX_DSET_X * MAX_DSET_Y * sizeof(unsigned); + + /* Allocate buffers */ + if(NULL == (rbuf = (unsigned *)HDmalloc(buf_size))) + T_PMD_ERROR + if(NULL == (erbuf = (unsigned *)HDmalloc(buf_size))) + T_PMD_ERROR + if(NULL == (wbuf = (unsigned *)HDmalloc(buf_size))) + T_PMD_ERROR + if(NULL == (efbuf = (unsigned *)HDmalloc(buf_size))) + T_PMD_ERROR + if(NULL == (dset_usage = (unsigned char *)HDmalloc(max_dsets * MAX_DSET_X * MAX_DSET_Y))) + T_PMD_ERROR + + /* Initialize buffer indices */ + for(i = 0; i < max_dsets; i++) + for(j = 0; j < MAX_DSET_X; j++) { + rbufi[i][j] = rbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + erbufi[i][j] = erbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + wbufi[i][j] = wbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + efbufi[i][j] = efbuf + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + dset_usagei[i][j] = dset_usage + (i * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_Y); + } /* end for */ + + /* Initialize 3rd dimension information (for tricking library into using + * non-"shapesame" code */ + for(i = 0; i < max_dsets; i++) + dset_dims[i][2] = 1; + for(i = 0; i < MAX_HS; i++) { + start[i][2] = 0; + count[i][2] = 1; + } /* end for */ + + /* Initialize multi_info */ + for(i = 0; i < max_dsets; i++) { + multi_info[i].dset_id = -1; + multi_info[i].dset_space_id = -1; + multi_info[i].mem_type_id = H5T_NATIVE_UINT; + multi_info[i].mem_space_id = -1; + } /* end for */ + + /* Generate memory dataspace */ + dset_dims[0][0] = MAX_DSET_X; + dset_dims[0][1] = MAX_DSET_Y; + if((multi_info[0].mem_space_id = H5Screate_simple((flags & MDSET_FLAG_SHAPESAME) ? 2 : 3, dset_dims[0], NULL)) < 0) + T_PMD_ERROR + for(i = 1; i < max_dsets; i++) + if((multi_info[i].mem_space_id = H5Scopy(multi_info[0].mem_space_id)) < 0) + T_PMD_ERROR + + /* Create fapl */ + if((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + T_PMD_ERROR + + /* Set MPIO file driver */ + if((H5Pset_fapl_mpio(fapl_id, MPI_COMM_WORLD, MPI_INFO_NULL)) < 0) + T_PMD_ERROR + + /* Create dcpl */ + if((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + T_PMD_ERROR + + /* Set fill time to alloc, and alloc time to early (so we always know + * what's in the file) */ + if(H5Pset_fill_time(dcpl_id, H5D_FILL_TIME_ALLOC) < 0) + T_PMD_ERROR + if(H5Pset_alloc_time(dcpl_id, H5D_ALLOC_TIME_EARLY) < 0) + T_PMD_ERROR + + /* Create dxpl */ + if((dxpl_id = H5Pcreate(H5P_DATASET_XFER)) < 0) + T_PMD_ERROR + + /* Set collective or independent I/O */ + if(flags & MDSET_FLAG_COLLECTIVE) { + if(H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE) < 0) + T_PMD_ERROR + } /* end if */ + else + if(H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_INDEPENDENT) < 0) + T_PMD_ERROR + + for(i = 0; i < niter; i++) { + /* Determine number of datasets */ + ndsets = (flags & MDSET_FLAG_MDSET) + ? (size_t)((size_t)HDrandom() % max_dsets) + 1 : 1; + + /* Create file */ + if((file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) + T_PMD_ERROR + + /* Create datasets */ + for(j = 0; j < ndsets; j++) { + /* Generate file dataspace */ + dset_dims[j][0] = (hsize_t)((HDrandom() % MAX_DSET_X) + 1); + dset_dims[j][1] = (hsize_t)((HDrandom() % MAX_DSET_Y) + 1); + if((multi_info[j].dset_space_id = H5Screate_simple(2, dset_dims[j], (flags & MDSET_FLAG_CHUNK) ? max_dims : NULL)) < 0) + T_PMD_ERROR + + /* Generate chunk (if requested) */ + if(flags & MDSET_FLAG_CHUNK) { + chunk_dims[0] = (hsize_t)((HDrandom() % MAX_CHUNK_X) + 1); + chunk_dims[1] = (hsize_t)((HDrandom() % MAX_CHUNK_Y) + 1); + if(H5Pset_chunk(dcpl_id, 2, chunk_dims) < 0) + T_PMD_ERROR + } /* end if */ + + /* Create dataset */ + if((multi_info[j].dset_id = H5Dcreate2(file_id, dset_name[j], H5T_NATIVE_UINT, multi_info[j].dset_space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) + T_PMD_ERROR + } /* end for */ + + /* Initialize read buffer and expected read buffer */ + (void)HDmemset(rbuf, 0, buf_size); + (void)HDmemset(erbuf, 0, buf_size); + + /* Initialize write buffer */ + for(j = 0; j < max_dsets; j++) + for(k = 0; k < MAX_DSET_X; k++) + for(l = 0; l < MAX_DSET_Y; l++) + wbufi[j][k][l] = (unsigned)(((unsigned)mpi_rank * max_dsets * MAX_DSET_X * MAX_DSET_Y) + (j * MAX_DSET_X * MAX_DSET_Y) + (k * MAX_DSET_Y) + l); + + /* Initialize expected file buffer */ + (void)HDmemset(efbuf, 0, buf_size); + + /* Set last_read to TRUE so we don't reopen the file on the first + * iteration */ + last_read = TRUE; + + /* Perform read/write operations */ + for(j = 0; j < OPS_PER_FILE; j++) { + /* Decide whether to read or write */ + do_read = (hbool_t)(HDrandom() % 2); + + /* Barrier to ensure processes have finished the previous operation + */ + MPI_Barrier(MPI_COMM_WORLD); + + /* If the last operation was a write we must close and reopen the + * file to ensure consistency */ + /* Possibly change to MPI_FILE_SYNC at some point? -NAF */ + if(!last_read) { + /* Close datasets */ + for(k = 0; k < ndsets; k++) { + if(H5Dclose(multi_info[k].dset_id) < 0) + T_PMD_ERROR + multi_info[k].dset_id = -1; + } /* end for */ + + /* Close file */ + if(H5Fclose(file_id) < 0) + T_PMD_ERROR + file_id = -1; + + /* Barrier */ + MPI_Barrier(MPI_COMM_WORLD); + + /* Reopen file */ + if((file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl_id)) < 0) + T_PMD_ERROR + + /* Reopen datasets */ + for(k = 0; k < ndsets; k++) { + if((multi_info[k].dset_id = H5Dopen2(file_id, dset_name[k], H5P_DEFAULT)) < 0) + T_PMD_ERROR + } /* end for */ + + /* Barrier */ + MPI_Barrier(MPI_COMM_WORLD); + } /* end if */ + + /* Keep track of whether the last operation was a read */ + last_read = do_read; + + /* Loop over datasets */ + for(k = 0; k < ndsets; k++) { + /* Reset selection */ + if(H5Sselect_none(multi_info[k].mem_space_id) < 0) + T_PMD_ERROR + if(H5Sselect_none(multi_info[k].dset_space_id) < 0) + T_PMD_ERROR + + /* Reset dataset usage array, if writing */ + if(!do_read) + HDmemset(dset_usage, 0, max_dsets * MAX_DSET_X * MAX_DSET_Y); + + /* Iterate over processes */ + for(l = 0; l < (size_t)mpi_size; l++) { + /* Calculate difference between data in process being + * iterated over and that in this process */ + rank_data_diff = (int)((unsigned)max_dsets * MAX_DSET_X * MAX_DSET_Y) * ((int)l - (int)mpi_rank); + + /* Decide whether to do a hyperslab or point selection */ + if(HDrandom() % 2) { + /* Hyperslab */ + size_t nhs = (size_t)((HDrandom() % MAX_HS) + 1); /* Number of hyperslabs */ + size_t max_hs_x = (MAX_HS_X <= dset_dims[k][0]) ? MAX_HS_X : dset_dims[k][0]; /* Determine maximum hyperslab size in X */ + size_t max_hs_y = (MAX_HS_Y <= dset_dims[k][1]) ? MAX_HS_Y : dset_dims[k][1]; /* Determine maximum hyperslab size in Y */ + + for(m = 0; m < nhs; m++) { + overlap = TRUE; + for(n = 0; overlap && (n < MAX_SEL_RETRIES); n++) { + /* Generate hyperslab */ + count[m][0] = (hsize_t)(((hsize_t)HDrandom() % max_hs_x) + 1); + count[m][1] = (hsize_t)(((hsize_t)HDrandom() % max_hs_y) + 1); + start[m][0] = (count[m][0] == dset_dims[k][0]) ? 0 + : (hsize_t)HDrandom() % (dset_dims[k][0] - count[m][0] + 1); + start[m][1] = (count[m][1] == dset_dims[k][1]) ? 0 + : (hsize_t)HDrandom() % (dset_dims[k][1] - count[m][1] + 1); + + /* If writing, check for overlap with other processes */ + overlap = FALSE; + if(!do_read) + for(o = start[m][0]; + (o < (start[m][0] + count[m][0])) && !overlap; + o++) + for(p = start[m][1]; + (p < (start[m][1] + count[m][1])) && !overlap; + p++) + if(dset_usagei[k][o][p]) + overlap = TRUE; + } /* end for */ + + /* If we did not find a non-overlapping hyperslab + * quit trying to generate new ones */ + if(overlap) { + nhs = m; + break; + } /* end if */ + + /* Select hyperslab if this is the current process + */ + if(l == (size_t)mpi_rank) { + if(H5Sselect_hyperslab(multi_info[k].mem_space_id, H5S_SELECT_OR, start[m], NULL, count[m], NULL) < 0) + T_PMD_ERROR + if(H5Sselect_hyperslab(multi_info[k].dset_space_id, H5S_SELECT_OR, start[m], NULL, count[m], NULL) < 0) + T_PMD_ERROR + } /* end if */ + + /* Update expected buffers */ + if(do_read) { + if(l == (size_t)mpi_rank) + for(n = start[m][0]; n < (start[m][0] + count[m][0]); n++) + for(o = start[m][1]; o < (start[m][1] + count[m][1]); o++) + erbufi[k][n][o] = efbufi[k][n][o]; + } /* end if */ + else + for(n = start[m][0]; n < (start[m][0] + count[m][0]); n++) + for(o = start[m][1]; o < (start[m][1] + count[m][1]); o++) + efbufi[k][n][o] = (unsigned)((int)wbufi[k][n][o] + rank_data_diff); + } /* end for */ + + /* Update dataset usage array if writing */ + if(!do_read) + for(m = 0; m < nhs; m++) + for(n = start[m][0]; n < (start[m][0] + count[m][0]); n++) + for(o = start[m][1]; o < (start[m][1] + count[m][1]); o++) + dset_usagei[k][n][o] = (unsigned char)1; + } /* end if */ + else { + /* Point selection */ + size_t npoints = (size_t)(((size_t)HDrandom() % MAX_POINTS) + 1); /* Number of points */ + + /* Generate points */ + for(m = 0; m < npoints; m++) { + overlap = TRUE; + for(n = 0; overlap && (n < MAX_SEL_RETRIES); n++) { + /* Generate point */ + points[2 * m] = (unsigned)((hsize_t)HDrandom() % dset_dims[k][0]); + points[(2 * m) + 1] = (unsigned)((hsize_t)HDrandom() % dset_dims[k][1]); + + /* If writing, check for overlap with other + * processes */ + overlap = FALSE; + if(!do_read) + if(dset_usagei[k][points[2 * m]][points[(2 * m) + 1]]) + overlap = TRUE; + } /* end for */ + + /* If we did not find a non-overlapping point quit + * trying to generate new ones */ + if(overlap) { + npoints = m; + break; + } /* end if */ + } /* end for */ + + /* Update dataset usage array if writing */ + if(!do_read) + for(m = 0; m < npoints; m++) + dset_usagei[k][points[2 * m]][points[(2 * m) + 1]] = (unsigned char)1; + + /* Select points in file if this is the current process + */ + if((l == (size_t)mpi_rank) && (npoints > 0)) + if(H5Sselect_elements(multi_info[k].dset_space_id, H5S_SELECT_APPEND, npoints, points) < 0) + T_PMD_ERROR + + /* Update expected buffers */ + if(do_read) { + if(l == (size_t)mpi_rank) + for(m = 0; m < npoints; m++) + erbufi[k][points[2 * m]][points[(2 * m) + 1]] = efbufi[k][points[2 * m]][points[(2 * m) + 1]]; + } /* end if */ + else + for(m = 0; m < npoints; m++) + efbufi[k][points[2 * m]][points[(2 * m) + 1]] = (unsigned)((int)wbufi[k][points[2 * m]][points[(2 * m) + 1]] + rank_data_diff); + + /* Select points in memory if this is the current + * process */ + if((l == (size_t)mpi_rank) && (npoints > 0)) { + /* Convert to 3D for memory selection, if not using + * "shapesame" */ + if(!(flags & MDSET_FLAG_SHAPESAME)) { + for(m = npoints - 1; m > 0; m--) { + points[(3 * m) + 2] = 0; + points[(3 * m) + 1] = points[(2 * m) + 1]; + points[3 * m] = points[2 * m]; + } /* end for */ + points[2] = 0; + } /* end if */ + + /* Select elements */ + if(H5Sselect_elements(multi_info[k].mem_space_id, H5S_SELECT_APPEND, npoints, points) < 0) + T_PMD_ERROR + } /* end if */ + } /* end else */ + } /* end for */ + } /* end for */ + + /* Perform I/O */ + if(do_read) { + if(flags & MDSET_FLAG_MDSET) { + /* Set buffers */ + for(k = 0; k < ndsets; k++) + multi_info[k].u.rbuf = rbufi[k][0]; + + /* Read datasets */ + if(H5Dread_multi(dxpl_id, ndsets, multi_info) < 0) + T_PMD_ERROR + } /* end if */ + else + /* Read */ + if(H5Dread(multi_info[0].dset_id, multi_info[0].mem_type_id, multi_info[0].mem_space_id, multi_info[0].dset_space_id, dxpl_id, rbuf) < 0) + T_PMD_ERROR + + /* Verify data */ + if(0 != memcmp(rbuf, erbuf, buf_size)) + T_PMD_ERROR + } /* end if */ + else { + if(flags & MDSET_FLAG_MDSET) { + /* Set buffers */ + for(k = 0; k < ndsets; k++) + multi_info[k].u.wbuf = wbufi[k][0]; + + /* Write datasets */ + if(H5Dwrite_multi(dxpl_id, ndsets, multi_info) < 0) + T_PMD_ERROR + } /* end if */ + else + /* Write */ + if(H5Dwrite(multi_info[0].dset_id, multi_info[0].mem_type_id, multi_info[0].mem_space_id, multi_info[0].dset_space_id, dxpl_id, wbuf) < 0) + T_PMD_ERROR + + /* Update wbuf */ + for(l = 0; l < max_dsets; l++) + for(m = 0; m < MAX_DSET_X; m++) + for(n = 0; n < MAX_DSET_Y; n++) + wbufi[l][m][n] += op_data_incr; + } /* end else */ + } /* end for */ + + /* Close */ + for(j = 0; j < ndsets; j++) { + if(H5Dclose(multi_info[j].dset_id) < 0) + T_PMD_ERROR + multi_info[j].dset_id = -1; + if(H5Sclose(multi_info[j].dset_space_id) < 0) + T_PMD_ERROR + multi_info[j].dset_space_id = -1; + } /* end for */ + if(H5Fclose(file_id) < 0) + T_PMD_ERROR + file_id = -1; + } /* end for */ + + /* Close */ + for(i = 0; i < max_dsets; i++) { + if(H5Sclose(multi_info[i].mem_space_id) < 0) + T_PMD_ERROR + multi_info[i].mem_space_id = -1; + } /* end for */ + if(H5Pclose(dxpl_id) < 0) + T_PMD_ERROR + dxpl_id = -1; + if(H5Pclose(dcpl_id) < 0) + T_PMD_ERROR + dcpl_id = -1; + if(H5Pclose(fapl_id) < 0) + T_PMD_ERROR + fapl_id = -1; + free(rbuf); + rbuf = NULL; + free(erbuf); + erbuf = NULL; + free(wbuf); + wbuf = NULL; + free(efbuf); + efbuf = NULL; + free(dset_usage); + dset_usage = NULL; + + if(mpi_rank == 0) + PASSED(); + + return; +} /* end test_mdset() */ + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Runs all tests with all combinations of configuration + * flags. + * + * Return: Success: 0 + * Failue: 1 + * + * Programmer: Neil Fortner + * Monday, March 10, 2014 + * + *------------------------------------------------------------------------- + */ +int +main(int argc, char *argv[]) +{ + unsigned i; + int ret; + + h5_reset(); + + /* Initialize MPI */ + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Generate random number seed, if rank 0 */ + if(MAINPROCESS) + seed = (unsigned)HDtime(NULL); + + /* Broadcast seed from rank 0 (other ranks will receive rank 0's seed) */ + if(MPI_SUCCESS != MPI_Bcast(&seed, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD)) + T_PMD_ERROR + + /* Seed random number generator with shared seed (so all ranks generate the + * same sequence) */ + HDsrandom(seed); + + /* Fill dset_name array */ + for(i = 0; i < MAX_DSETS; i++) { + if((ret = snprintf(dset_name[i], DSET_MAX_NAME_LEN, "dset%u", i)) < 0) + T_PMD_ERROR + if(ret >= DSET_MAX_NAME_LEN) + T_PMD_ERROR + } /* end for */ + + for(i = 0; i <= MDSET_ALL_FLAGS; i++) { + /* Print flag configuration */ + if(MAINPROCESS) { + puts("\nConfiguration:"); + printf(" Layout: %s\n", (i & MDSET_FLAG_CHUNK) ? "Chunked" : "Contiguous"); + printf(" Shape same: %s\n", (i & MDSET_FLAG_SHAPESAME) ? "Yes" : "No"); + printf(" I/O type: %s\n", (i & MDSET_FLAG_MDSET) ? "Multi" : "Single"); + printf(" MPI I/O type: %s\n", (i & MDSET_FLAG_COLLECTIVE) ? "Collective" : "Independent"); + } /* end if */ + + test_pmdset(10, i); + } /* end for */ + + /* Barrier to make sure all ranks are done before deleting the file, and + * also to clean up output (make sure PASSED is printed before any of the + * following messages) */ + if(MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) + T_PMD_ERROR + + /* Delete file */ + if(mpi_rank == 0) + if(MPI_SUCCESS != MPI_File_delete(FILENAME, MPI_INFO_NULL)) + T_PMD_ERROR + + /* Gather errors from all processes */ + MPI_Allreduce(&nerrors, &ret, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); + nerrors = ret; + + if(MAINPROCESS) { + printf("===================================\n"); + if (nerrors) + printf("***Parallel multi dataset tests detected %d errors***\n", nerrors); + else + printf("Parallel multi dataset tests finished with no errors\n"); + printf("===================================\n"); + } /* end if */ + + /* close HDF5 library */ + H5close(); + + /* MPI_Finalize must be called AFTER H5close which may use MPI calls */ + MPI_Finalize(); + + /* cannot just return (nerrors) because exit code is limited to 1 byte */ + return(nerrors != 0); +} /* end main() */ + diff --git a/testpar/testphdf5.c b/testpar/testphdf5.c index 87d9056..abd09ea 100644 --- a/testpar/testphdf5.c +++ b/testpar/testphdf5.c @@ -383,11 +383,12 @@ int main(int argc, char **argv) "parallel extend Chunked allocation on serial file", PARATESTFILE); AddTest("fltread", test_filter_read, NULL, "parallel read of dataset written serially with filters", PARATESTFILE); - +#if 0 //MSB FIX #ifdef H5_HAVE_FILTER_DEFLATE AddTest("cmpdsetr", compress_readAll, NULL, "compressed dataset collective read", PARATESTFILE); #endif /* H5_HAVE_FILTER_DEFLATE */ +#endif AddTest("zerodsetr", zero_dim_dset, NULL, "zero dim dset", PARATESTFILE); @@ -439,23 +440,6 @@ int main(int argc, char **argv) AddTest((mpi_size <3)? "-cchunk5":"cchunk5" , coll_chunk5,NULL, "linked chunk collective IO without optimization",PARATESTFILE); - AddTest((mpi_size < 3)? "-cchunk6" : "cchunk6", - coll_chunk6,NULL, - "multi-chunk collective IO with direct request",PARATESTFILE); - AddTest((mpi_size < 3)? "-cchunk7" : "cchunk7", - coll_chunk7,NULL, - "linked chunk collective IO with optimization",PARATESTFILE); - AddTest((mpi_size < 3)? "-cchunk8" : "cchunk8", - coll_chunk8,NULL, - "linked chunk collective IO transferring to multi-chunk",PARATESTFILE); - AddTest((mpi_size < 3)? "-cchunk9" : "cchunk9", - coll_chunk9,NULL, - "multiple chunk collective IO with optimization",PARATESTFILE); - AddTest((mpi_size < 3)? "-cchunk10" : "cchunk10", - coll_chunk10,NULL, - "multiple chunk collective IO transferring to independent IO",PARATESTFILE); - - /* irregular collective IO tests*/ AddTest("ccontw", diff --git a/testpar/testphdf5.h b/testpar/testphdf5.h index 322cb9b..ec61c58 100644 --- a/testpar/testphdf5.h +++ b/testpar/testphdf5.h @@ -168,14 +168,8 @@ enum H5TEST_COLL_CHUNK_API {API_NONE=0,API_LINK_HARD, /* Definitions of the selection mode for the test_actual_io_function. */ #define TEST_ACTUAL_IO_NO_COLLECTIVE 0 #define TEST_ACTUAL_IO_RESET 1 -#define TEST_ACTUAL_IO_MULTI_CHUNK_IND 2 -#define TEST_ACTUAL_IO_MULTI_CHUNK_COL 3 -#define TEST_ACTUAL_IO_MULTI_CHUNK_MIX 4 -#define TEST_ACTUAL_IO_MULTI_CHUNK_MIX_DISAGREE 5 -#define TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_IND 6 -#define TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_COL 7 -#define TEST_ACTUAL_IO_LINK_CHUNK 8 -#define TEST_ACTUAL_IO_CONTIGUOUS 9 +#define TEST_ACTUAL_IO_LINK_CHUNK 2 +#define TEST_ACTUAL_IO_CONTIGUOUS 3 /* Definitions of the selection mode for the no_collective_cause_tests function. */ #define TEST_COLLECTIVE 0x001 diff --git a/tools/test/h5dump/errfiles/filter_fail.err b/tools/test/h5dump/errfiles/filter_fail.err index db21044..afcbbe1 100644 --- a/tools/test/h5dump/errfiles/filter_fail.err +++ b/tools/test/h5dump/errfiles/filter_fail.err @@ -1,20 +1,23 @@ HDF5-DIAG: Error detected in HDF5 (version (number)) thread (IDs): - #000: (file name) line (number) in H5Dread(): can't read data + #000: (file name) line (number) in H5Dread(): can't prepare for reading data major: Dataset minor: Read failed - #001: (file name) line (number) in H5D__read(): can't read data + #001: (file name) line (number) in H5D__pre_read(): can't read data major: Dataset minor: Read failed - #002: (file name) line (number) in H5D__chunk_read(): unable to read raw data chunk + #002: (file name) line (number) in H5D__read(): can't read data + major: Dataset + minor: Read failed + #003: (file name) line (number) in H5D__chunk_read(): unable to read raw data chunk major: Low-level I/O minor: Read failed - #003: (file name) line (number) in H5D__chunk_lock(): data pipeline read failed + #004: (file name) line (number) in H5D__chunk_lock(): data pipeline read failed major: Data filters minor: Filter operation failed - #004: (file name) line (number) in H5Z_pipeline(): required filter 'filter_fail_test' is not registered + #005: (file name) line (number) in H5Z_pipeline(): required filter 'filter_fail_test' is not registered major: Data filters minor: Read failed - #005: (file name) line (number) in H5PL_load(): required dynamically loaded plugin filter '312' is not available + #006: (file name) line (number) in H5PL_load(): required dynamically loaded plugin filter '312' is not available major: Plugin for dynamically loaded library minor: Unable to load metadata into cache h5dump error: unable to print data |