//$ mpicc mpitest.c -o mpitest -std=c99 -lhdf5 -DMPI_DEBUG //$ NDOMAINS=2 mpirun -np 4 ./mpitest // http://www.hdfgroup.org/ftp/HDF5/examples/examples-by-api/hdf5-examples/1_8/C/H5D/ #include #include #include #include #include #include #include #include typedef struct { int rank; int size; int *members; MPI_Comm comm; MPI_Group group; void *parent; } MPI_Object; typedef struct { int start; int stop; int step; } slice; int take(slice s, int idx) { int count = s.stop-s.start; assert(0 <= idx && idx < count); return s.start + idx*s.step; } // ------------------------------------------------------------------ const char datfile[] = "parallelc.hdf5"; const char logfile[] = "parallelc.log"; static int devnull; #define H5RUN(x,y) if((x=y) < 0) { fprintf(stderr, "H5 %s:%d returned %d.\n", __FILE__, __LINE__, x); return -1; } #define MPIRUN(x,y) if((x=y) != MPI_SUCCESS) { fprintf(stderr, "MPI %s:%d returned %d.\n", __FILE__, __LINE__, x); return -1; } #define MPI_WAIT_ORDERED 10000 #define MPI_PRE_ORDERED(comm_obj) \ for(int i=0; i<(comm_obj).rank; i++) { \ MPI_Barrier((comm_obj).comm); \ usleep(MPI_WAIT_ORDERED); \ } #define MPI_POST_ORDERED(comm_obj) \ for(int i=(comm_obj).rank; i<(comm_obj).size; i++) { \ usleep(MPI_WAIT_ORDERED); \ MPI_Barrier((comm_obj).comm); \ } // ------------------------------------------------------------------ typedef struct { int nbands; int mynbands; MPI_Object comm; } BandDescriptor; BandDescriptor new_band_descriptor(MPI_Object band_comm) { BandDescriptor bd; bd.nbands = 24; // Determine band descriptors (from band_descriptor.py) bd.mynbands = bd.nbands / band_comm.size; assert(bd.mynbands * band_comm.size == bd.nbands); bd.comm = band_comm; return bd; } // ------------------------------------------------------------------ typedef struct { int N_c[3]; // global number of grid points per axis incl. padding bool pbc_c[3]; int parsize_c[3]; int parpos_c[3]; double h_c[3]; int beg_c[3]; int end_c[3]; int n_c[3]; // local number of grid points per axis int gpts_c[3]; // global number of grid points per axis MPI_Object comm; } GridDescriptor; GridDescriptor new_grid_descriptor(MPI_Object domain_comm) { GridDescriptor gd; gd.N_c[0] = gd.N_c[1] = gd.N_c[2] = 12; gd.pbc_c[0] = gd.pbc_c[1] = gd.pbc_c[2] = false; // Determine domain decomposition (from domain.py) gd.parsize_c[0] = domain_comm.size; gd.parsize_c[1] = gd.parsize_c[2] = 1; assert(gd.parsize_c[0] * gd.parsize_c[1] * gd.parsize_c[2] == domain_comm.size); gd.parpos_c[0] = domain_comm.rank / (gd.parsize_c[1] * gd.parsize_c[2]); gd.parpos_c[1] = (domain_comm.rank % (gd.parsize_c[1] * gd.parsize_c[2])) / gd.parsize_c[2]; gd.parpos_c[2] = domain_comm.rank % gd.parsize_c[2]; assert(gd.parpos_c[0] * gd.parsize_c[1] * gd.parsize_c[2] \ + gd.parpos_c[1] * gd.parsize_c[2] \ + gd.parpos_c[2] == domain_comm.rank); // Determine grid descriptors (from grid_descriptor.py) gd.h_c[0] = gd.h_c[1] = gd.h_c[2] = 0.2; for(int c=0; c<3; c++) { double tmp; int n = gd.parsize_c[c]+1, *p = malloc(n*sizeof(int)); for(int i=0; i0); assert((int) simple>0); int refnpts = 1; for(int i=0; i0); assert((int) simple>0); int refnpts = 1; for(int i=0; i 1) { // Copy MPI information to the file access property list (driver) char buf[20]; snprintf(buf, 20, "%d", world.size); MPIRUN(devnull, MPI_Info_create(&info)); MPIRUN(devnull, MPI_Info_set(info, "cb_nodes", buf)); //H5RUN(devnull, H5FD_mpio_init()); H5RUN(devnull, H5Pset_fapl_mpio(fapl_id, world.comm, info)); } else { H5RUN(devnull, H5Pset_fapl_stdio(fapl_id)); //H5RUN(devnull, H5Pset_fapl_log(fapl_id, logfile, H5FD_LOG_ALL, 256*1024)); } // Create file in write-mode using the file access property list from above H5RUN(f_id, H5Fcreate(datfile, H5F_ACC_TRUNC /*'w'*/, H5P_DEFAULT /*fcpl*/, fapl_id /*fapl*/)); // Speficy collective I/O for data transfer property list H5RUN(dxpl_id, H5Pcreate(H5P_DATASET_XFER)); if(world.size > 1) { H5RUN(devnull, H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE)); //H5RUN(devnull, H5Pset_dxpl_mpio_chunk_opt(dxpl_id, H5FD_MPIO_CHUNK_MULTI_IO)); //new in 1.8x? //H5RUN(devnull, H5Pset_buffer(dxpl_id, 32*1024*1024)); //set transfer buffer to 32mb } // Specify early allocation for dataset creation property list if serial H5RUN(dcpl_id, H5Pcreate(H5P_DATASET_CREATE)); H5RUN(devnull, H5Pset_fill_time(dcpl_id, H5D_FILL_TIME_NEVER)); if(world.size == 1) { H5RUN(devnull, H5Pset_alloc_time(dcpl_id, H5D_ALLOC_TIME_EARLY)); } hid_t dset_id = 0, dtype_id = 0, fspace_id = 0, mspace_id = 0; if(psit_nG) { if(world.rank == 0) { printf("\npsit_nG\n"); fflush(stdout); } hsize_t count[] = {bd.mynbands, gd.n_c[0], gd.n_c[1], gd.n_c[2]}, start[] = {indices[0].start, indices[1].start, indices[2].start, indices[3].start}, fshape[] = {bd.nbands, gd.gpts_c[0], gd.gpts_c[1], gd.gpts_c[2]}; // Create reduced-size memory dataspace H5RUN(mspace_id, H5Screate_simple(4, (const hsize_t*) count, NULL)); check_mspace(world, mspace_id, bd, gd, 4, (const hsize_t*) count); // Create fixed-size file dataspace H5RUN(fspace_id, H5Screate_simple(4, (const hsize_t*) fshape, (const hsize_t*) NULL)); // max_shape??? // Select the hyperslab that memory dataspace represents in file dataspace H5RUN(devnull, H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET /*op*/, (const hsize_t*) start, (const hsize_t*) NULL /*stride*/, (const hsize_t*) count, (const hsize_t*) NULL /*block*/)); //H5RUN(devnull, H5Sselect_none(fspace_id)); //H5RUN(devnull, H5Soffset_simple(fspace_id, (const hsize_t*) zeros)); check_fspace(world, fspace_id, bd, gd, 4, (const hsize_t*) fshape); // Create datatype and verify size and order H5RUN(dtype_id, H5Tcopy(H5T_NATIVE_DOUBLE)); H5RUN(devnull, H5Tset_order(dtype_id, H5T_ORDER_LE)); assert(H5Tget_size(dtype_id) == sizeof(double)); // Create psit_nG dataset H5RUN(dset_id, H5Dcreate(f_id, "PseudoWaveFunctions", dtype_id /*ftype*/, fspace_id /*fspace*/, dcpl_id /*dcpl*/)); check_dset(world, dset_id, bd, gd, 4, (const hsize_t*) fshape, sizeof(double)); H5RUN(devnull, H5Dwrite(dset_id, dtype_id /*mtype*/, mspace_id /*mspace*/, fspace_id /*fspace*/, dxpl_id /*dxpl*/, psit_nG)); // Close all open ids H5RUN(devnull, H5Dclose(dset_id)); H5RUN(devnull, H5Tclose(dtype_id)); H5RUN(devnull, H5Sclose(fspace_id)); H5RUN(devnull, H5Sclose(mspace_id)); } if(big_rhot_G) { if(world.rank == 0) { printf("\nbig_rhot_G\n"); fflush(stdout); } hsize_t count[] = {gd.gpts_c[0], gd.gpts_c[1], gd.gpts_c[2]}, start[] = {0, 0, 0}, fshape[] = {gd.gpts_c[0], gd.gpts_c[1], gd.gpts_c[2]}; // Create reduced-size memory dataspace H5RUN(mspace_id, H5Screate_simple(3, (const hsize_t*) count, NULL)); if(domain_comm.rank != 0) { H5RUN(devnull, H5Sselect_none(mspace_id)); } check_mspace(world, mspace_id, bd, gd, 3, (const hsize_t*) count); // Create fixed-size file dataspace H5RUN(fspace_id, H5Screate_simple(3, (const hsize_t*) fshape, (const hsize_t*) NULL)); // max_shape??? // Select the hyperslab that memory dataspace represents in file dataspace if(domain_comm.rank == 0) { H5RUN(devnull, H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET /*op*/, (const hsize_t*) start, (const hsize_t*) NULL /*stride*/, (const hsize_t*) count, (const hsize_t*) NULL /*block*/)); } else { H5RUN(devnull, H5Sselect_none(fspace_id)); } //H5RUN(devnull, H5Soffset_simple(fspace_id, (const hsize_t*) zeros)); check_fspace(world, fspace_id, bd, gd, 3, (const hsize_t*) fshape); // Create datatype and verify size and order H5RUN(dtype_id, H5Tcopy(H5T_NATIVE_DOUBLE)); H5RUN(devnull, H5Tset_order(dtype_id, H5T_ORDER_LE)); assert(H5Tget_size(dtype_id) == sizeof(double)); // Create psit_nG dataset H5RUN(dset_id, H5Dcreate(f_id, "PseudoChargeDensity", dtype_id /*ftype*/, fspace_id /*fspace*/, dcpl_id /*dcpl*/)); check_dset(world, dset_id, bd, gd, 3, (const hsize_t*) fshape, sizeof(double)); H5RUN(devnull, H5Dwrite(dset_id, dtype_id /*mtype*/, mspace_id /*mspace*/, fspace_id /*fspace*/, dxpl_id /*dxpl*/, big_rhot_G)); // Close all open ids H5RUN(devnull, H5Dclose(dset_id)); H5RUN(devnull, H5Tclose(dtype_id)); H5RUN(devnull, H5Sclose(fspace_id)); H5RUN(devnull, H5Sclose(mspace_id)); } // Close remaining ids H5RUN(devnull, H5Pclose(dcpl_id)); H5RUN(devnull, H5Pclose(dxpl_id)); H5RUN(devnull, H5Pclose(fapl_id)); if(world.size > 1) MPIRUN(devnull, MPI_Info_free(&info)); H5RUN(devnull, H5Fclose(f_id)); free(psit_nG); free(big_rhot_G); fflush(stdout); MPI_Barrier(world.comm); return 0; } // ------------------------------------------------------------------ int run_read(MPI_Object world, MPI_Object domain_comm, MPI_Object band_comm) { // Print ordered processor distribution MPI_PRE_ORDERED(world); printf("READ: %d/%d, gd: %d/%d, bd: %d/%d\n", world.rank, world.size, domain_comm.rank, domain_comm.size, band_comm.rank, band_comm.size); fflush(stdout); MPI_POST_ORDERED(world); GridDescriptor gd = new_grid_descriptor(domain_comm); BandDescriptor bd = new_band_descriptor(band_comm); // Set up slices slice *indices = malloc(4*sizeof(slice)); indices[0].start = band_comm.rank * bd.mynbands; indices[0].stop = indices[0].start + bd.mynbands; indices[0].step = 1; for(int c=0; c<3; c++) { indices[c+1].start = gd.beg_c[c] - 1 + gd.pbc_c[c]; indices[c+1].stop = gd.end_c[c] - 1 + gd.pbc_c[c]; indices[c+1].step = 1; } // Allocate buffer for bogus but reproducible data in local domain int myngpts = gd.n_c[0] * gd.n_c[1] * gd.n_c[2]; double *psit_nG = malloc(bd.mynbands * myngpts * sizeof(double)); if(!psit_nG) return -1; // Allocate buffer for bogus but reproducible data on domain masters int ngpts = gd.gpts_c[0] * gd.gpts_c[1] * gd.gpts_c[2]; double *big_rhot_G = malloc(ngpts * sizeof(double)); if(!big_rhot_G) return -1; hid_t fapl_id = 0, f_id = 0, dxpl_id = 0; // File access property list (from io/hdf5.py) MPI_Info info; H5RUN(fapl_id, H5Pcreate(H5P_FILE_ACCESS)); #ifndef MPI_DEBUG H5RUN(devnull, H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG)); #endif if(world.size > 1) { // Copy MPI information to the file access property list (driver) char buf[20]; snprintf(buf, 20, "%d", world.size); MPIRUN(devnull, MPI_Info_create(&info)); MPIRUN(devnull, MPI_Info_set(info, "cb_nodes", buf)); //H5RUN(devnull, H5FD_mpio_init()); H5RUN(devnull, H5Pset_fapl_mpio(fapl_id, world.comm, info)); } else H5RUN(devnull, H5Pset_fapl_stdio(fapl_id)); //H5RUN(devnull, H5Pset_fapl_log(fapl_id, logfile, H5FD_LOG_ALL, 256*1024)); // Create file in write-mode using the file access property list from above H5RUN(f_id, H5Fopen(datfile, H5F_ACC_RDONLY /*'r'*/, fapl_id /*fapl*/)); // Speficy collective I/O for data transfer property list H5RUN(dxpl_id, H5Pcreate(H5P_DATASET_XFER)); if(world.size > 1) { H5RUN(devnull, H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE)); //H5RUN(devnull, H5Pset_dxpl_mpio_chunk_opt(dxpl_id, H5FD_MPIO_CHUNK_MULTI_IO)); //new in 1.8x? //H5RUN(devnull, H5Pset_buffer(dxpl_id, 32*1024*1024)); //set transfer buffer to 32mb } hid_t dset_id = 0, dtype_id = 0, fspace_id = 0, mspace_id = 0; if(psit_nG) { if(world.rank == 0) { printf("\npsit_nG\n"); fflush(stdout); } hsize_t refsize[] = {bd.nbands, gd.gpts_c[0], gd.gpts_c[1], gd.gpts_c[2]}, count[] = {bd.mynbands, gd.n_c[0], gd.n_c[1], gd.n_c[2]}, start[] = {indices[0].start, indices[1].start, indices[2].start, indices[3].start}; // Open psit_nG dataset H5RUN(dset_id, H5Dopen(f_id, "PseudoWaveFunctions")); check_dset(world, dset_id, bd, gd, 4, (const hsize_t*) refsize, sizeof(double)); // Open datatype and verify size and order H5RUN(dtype_id, H5Dget_type(dset_id)); assert((int) H5Tequal(dtype_id, H5T_NATIVE_DOUBLE) > 0); assert(H5Tget_size(dtype_id) == sizeof(double)); assert(H5Tget_order(dtype_id) == H5T_ORDER_LE); // Open file dataspace and verify fixed size H5RUN(fspace_id, H5Dget_space(dset_id)); assert(H5Sget_simple_extent_ndims(fspace_id) == 4); hsize_t fshape[4]; // Select the hyperslab that memory dataspace represents in file dataspace H5RUN(devnull, H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET /*op*/, (const hsize_t*) start, (const hsize_t*) NULL /*stride*/, (const hsize_t*) count, (const hsize_t*) NULL /*block*/)); //H5RUN(devnull, H5Sselect_none(fspace_id)); //H5RUN(devnull, H5Soffset_simple(fspace_id, (const hsize_t*) zeros)); check_fspace(world, fspace_id, bd, gd, 4, (const hsize_t*) refsize); // Create reduced-size memory dataspace H5RUN(mspace_id, H5Screate_simple(4, (const hsize_t*) count, NULL)); check_mspace(world, mspace_id, bd, gd, 4, (const hsize_t*) count); H5RUN(devnull, H5Dread(dset_id, dtype_id /*mtype*/, mspace_id /*mspace*/, fspace_id /*fspace*/, dxpl_id /*dxpl*/, psit_nG)); // Close all open ids H5RUN(devnull, H5Dclose(dset_id)); H5RUN(devnull, H5Tclose(dtype_id)); H5RUN(devnull, H5Sclose(fspace_id)); H5RUN(devnull, H5Sclose(mspace_id)); } if(big_rhot_G) { if(world.rank == 0) { printf("\nbig_rhot_G\n"); fflush(stdout); } hsize_t refsize[] = {gd.gpts_c[0], gd.gpts_c[1], gd.gpts_c[2]}, count[] = {gd.gpts_c[0], gd.gpts_c[1], gd.gpts_c[2]}, start[] = {0, 0, 0}; // Open psit_nG dataset H5RUN(dset_id, H5Dopen(f_id, "PseudoChargeDensity")); check_dset(world, dset_id, bd, gd, 3, (const hsize_t*) refsize, sizeof(double)); // Open datatype and verify size and order H5RUN(dtype_id, H5Dget_type(dset_id)); assert((int) H5Tequal(dtype_id, H5T_NATIVE_DOUBLE) > 0); assert(H5Tget_size(dtype_id) == sizeof(double)); assert(H5Tget_order(dtype_id) == H5T_ORDER_LE); // Open file dataspace and verify fixed size H5RUN(fspace_id, H5Dget_space(dset_id)); assert(H5Sget_simple_extent_ndims(fspace_id) == 3); hsize_t fshape[3]; // Select the hyperslab that memory dataspace represents in file dataspace if(domain_comm.rank == 0) { H5RUN(devnull, H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET /*op*/, (const hsize_t*) start, (const hsize_t*) NULL /*stride*/, (const hsize_t*) count, (const hsize_t*) NULL /*block*/)); } else { H5RUN(devnull, H5Sselect_none(fspace_id)); } //H5RUN(devnull, H5Soffset_simple(fspace_id, (const hsize_t*) zeros)); check_fspace(world, fspace_id, bd, gd, 3, (const hsize_t*) refsize); // Create reduced-size memory dataspace H5RUN(mspace_id, H5Screate_simple(3, (const hsize_t*) count, NULL)); if(domain_comm.rank != 0) { H5RUN(devnull, H5Sselect_none(mspace_id)); } check_mspace(world, mspace_id, bd, gd, 3, (const hsize_t*) count); H5RUN(devnull, H5Dread(dset_id, dtype_id /*mtype*/, mspace_id /*mspace*/, fspace_id /*fspace*/, dxpl_id /*dxpl*/, big_rhot_G)); // Close all open ids H5RUN(devnull, H5Dclose(dset_id)); H5RUN(devnull, H5Tclose(dtype_id)); H5RUN(devnull, H5Sclose(fspace_id)); H5RUN(devnull, H5Sclose(mspace_id)); } H5RUN(devnull, H5Pclose(dxpl_id)); H5RUN(devnull, H5Pclose(fapl_id)); if(world.size > 1) MPIRUN(devnull, MPI_Info_free(&info)); H5RUN(devnull, H5Fclose(f_id)); if(psit_nG) { // Verify read data against bogus but reproducible equivalent double tmp, tmp2, r0_v[3]; for(int myn=0; myn