/********************************************************************* * * Copyright (C) 2014, Northwestern University and Argonne National Laboratory * See COPYRIGHT notice in top-level directory. * *********************************************************************/ /* $Id$ */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This example, generalized from column_wise.cpp, makes a number of nonblocking * API calls, each writes a block of columns into a 2D integer array. In other * words, the I/O pattern is a blocked cyclic along X dimension. * * Each process writes NX columns in total. The block length is controlled by * block_len. In this example, block_len is set to 2. Blocks are layout in a * cyclic fashion in the file. This example can test if PnetCDF can coalesce * file offsets and lengths when constructing a merged filetype. * * The compile and run commands are given below, together with an ncmpidump of * the output file. In this example, block_len = 2. * * % mpicxx -O2 -o block_cyclic block_cyclic.cpp -lpnetcdf * % mpiexec -l -n 4 ./block_cyclic /pvfs2/wkliao/testfile.nc * 0: 0: NY=10 myNX= 4 myOff= 0 * 1: 1: NY=10 myNX= 4 myOff= 4 * 2: 2: NY=10 myNX= 4 myOff= 8 * 3: 3: NY=10 myNX= 4 myOff= 12 * 0: [i=0] iput() start= 0 0 count= 10 1 * 0: [i=1] iput() start= 0 1 count= 10 1 * 0: [i=2] iput() start= 0 8 count= 10 1 * 0: [i=3] iput() start= 0 9 count= 10 1 * 1: [i=0] iput() start= 0 2 count= 10 1 * 1: [i=1] iput() start= 0 3 count= 10 1 * 1: [i=2] iput() start= 0 10 count= 10 1 * 1: [i=3] iput() start= 0 11 count= 10 1 * 2: [i=0] iput() start= 0 4 count= 10 1 * 2: [i=1] iput() start= 0 5 count= 10 1 * 2: [i=2] iput() start= 0 12 count= 10 1 * 2: [i=3] iput() start= 0 13 count= 10 1 * 3: [i=0] iput() start= 0 6 count= 10 1 * 3: [i=1] iput() start= 0 7 count= 10 1 * 3: [i=2] iput() start= 0 14 count= 10 1 * 3: [i=3] iput() start= 0 15 count= 10 1 * * % ncmpidump /pvfs2/wkliao/testfile.nc * netcdf testfile { * // file format: CDF-5 (big variables) * dimensions: * Y = 10 ; * X = 16 ; * variables: * int var(Y, X) ; * data: * * var = * 10, 10, 11, 11, 12, 12, 13, 13, 10, 10, 11, 11, 12, 12, 13, 13, * 10, 10, 11, 11, 12, 12, 13, 13, 10, 10, 11, 11, 12, 12, 13, 13, * 10, 10, 11, 11, 12, 12, 13, 13, 10, 10, 11, 11, 12, 12, 13, 13, * 10, 10, 11, 11, 12, 12, 13, 13, 10, 10, 11, 11, 12, 12, 13, 13, * 10, 10, 11, 11, 12, 12, 13, 13, 10, 10, 11, 11, 12, 12, 13, 13, * 10, 10, 11, 11, 12, 12, 13, 13, 10, 10, 11, 11, 12, 12, 13, 13, * 10, 10, 11, 11, 12, 12, 13, 13, 10, 10, 11, 11, 12, 12, 13, 13, * 10, 10, 11, 11, 12, 12, 13, 13, 10, 10, 11, 11, 12, 12, 13, 13, * 10, 10, 11, 11, 12, 12, 13, 13, 10, 10, 11, 11, 12, 12, 13, 13, * 10, 10, 11, 11, 12, 12, 13, 13, 10, 10, 11, 11, 12, 12, 13, 13 ; * } * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include using namespace std; #include /* strcpy(), strncpy() */ #include /* getopt() */ #include using namespace PnetCDF; using namespace PnetCDF::exceptions; #define NY 10 #define NX 4 #define MIN(a,b) (((a)<(b))?(a):(b)) static void usage(char *argv0) { cerr << "Usage: %s [-h] | [-q] [file_name]\n" " [-h] Print help\n" " [-q] Quiet mode (reports when fail)\n" " [filename] output netCDF file name\n" << argv0; } int main(int argc, char** argv) { extern int optind; char filename[256]; int i, j, verbose=1, rank, nprocs, num_reqs; int *reqs, *sts, **buf; MPI_Offset myNX, G_NX, myOff, block_start, block_len; vector start(2), count(2); int bb_enabled=0; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &nprocs); /* get command-line arguments */ while ((i = getopt(argc, argv, "hq")) != EOF) switch(i) { case 'q': verbose = 0; break; case 'h': default: if (rank==0) usage(argv[0]); MPI_Finalize(); return 1; } if (argv[optind] == NULL) strcpy(filename, "testfile.nc"); else snprintf(filename, 256, "%s", argv[optind]); try { /* create a new file for writing ------------------------------------*/ NcmpiFile nc(MPI_COMM_WORLD, filename, NcmpiFile::replace, NcmpiFile::classic5); { int flag; char hint[MPI_MAX_INFO_VAL]; MPI_Info infoused; nc.Inq_file_info(&infoused); MPI_Info_get(infoused, (char*)"nc_burst_buf", MPI_MAX_INFO_VAL - 1, hint, &flag); if (flag && strcasecmp(hint, "enable") == 0) bb_enabled = 1; MPI_Info_free(&infoused); } /* the global array is NY * (NX * nprocs) */ G_NX = NX * nprocs; myOff = NX * rank; myNX = NX; if (verbose) printf("%2d: NY=%d myNX=%3lld myOff=%3lld\n",rank,NY,myNX,myOff); /* define dimensions x and y */ vector dimid(2); dimid[0] = nc.addDim("Y", NY); dimid[1] = nc.addDim("X", G_NX); /* define a 2D variable of integer type */ NcmpiVar var = nc.addVar("var", ncmpiInt, dimid); /* First, fill the entire array with zeros, using a blocking I/O. Every process writes a subarray of size NY * myNX */ buf = (int**) malloc(myNX * sizeof(int*)); buf[0] = (int*) calloc(NY * myNX, sizeof(int)); start[0] = 0; start[1] = myOff; count[0] = NY; count[1] = myNX; var.putVar_all(start, count, &buf[0][0]); free(buf[0]); if (bb_enabled) { nc.flush(); } /* initialize the buffer with rank ID. Also make the case interesting, by allocating buffers separately */ for (i=0; i myNX) block_len = myNX; start[0] = 0; start[1] = rank * block_len; count[0] = NY; count[1] = 1; num_reqs = 0; for (i=0; i 0) buf[i] = buf[i-1] + NY; for (j=0; j myNX) block_len = myNX; start[0] = 0; start[1] = rank * block_len; count[0] = NY; count[1] = 1; num_reqs = 0; for (i=0; i 0) printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n", sum_size); } MPI_Finalize(); return 0; }