1 /*********************************************************************
2 *
3 * Copyright (C) 2013, Northwestern University and Argonne National Laboratory
4 * See COPYRIGHT notice in top-level directory.
5 *
6 *********************************************************************/
7 /* $Id: put_varn_int.c 2717 2016-12-18 01:20:47Z wkliao $ */
8
9 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
10 * This example shows how to use a single call of ncmpi_put_varn_int_all() to
11 * write a sequence of requests with arbitrary array indices and lengths.
12 * Using ncmpi_put_varn_int_all() can achieve the same effect of HDF5 writing
13 * a sequence of selected file locations through the following 2 APIs.
14 *
15 * H5Sselect_elements(fid, H5S_SELECT_SET, NUMP, (const hssize_t **)coord);
16 * H5Dwrite(dataset, H5T_NATIVE_INT, mid, fid, H5P_DEFAULT, val);
17 *
18 * Note that in ncmpi_put_varn_int_all(), users can write more than one
19 * element starting at each selected location.
20 *
21 * The compile and run commands are given below, together with an ncmpidump of
22 * the output file.
23 *
24 * % mpicc -O2 -o put_varn_int put_varn_int.c -lpnetcdf
25 * % mpiexec -n 4 ./put_varn_int /pvfs2/wkliao/testfile.nc
26 * % ncmpidump /pvfs2/wkliao/testfile.nc
27 * netcdf testfile {
28 * // file format: CDF-5 (big variables)
29 * dimensions:
30 * Y = 4 ;
31 * X = 10 ;
32 * variables:
33 * int var(Y, X) ;
34 * data:
35 *
36 * var =
37 * 3, 3, 3, 1, 1, 0, 0, 2, 1, 1,
38 * 0, 2, 2, 2, 3, 1, 1, 2, 2, 2,
39 * 1, 1, 2, 3, 3, 3, 0, 0, 1, 1,
40 * 0, 0, 0, 2, 1, 1, 1, 3, 3, 3 ;
41 * }
42 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h> /* strcpy(), strncpy() */
47 #include <unistd.h> /* getopt() */
48 #include <mpi.h>
49 #include <pnetcdf.h>
50
51 #ifndef MPI_OFFSET
52 #define MPI_OFFSET MPI_LONG_LONG_INT
53 #endif
54
55 #define NY 4
56 #define NX 10
57 #define NDIMS 2
58
59 #define ERR {if(err!=NC_NOERR){printf("Error at line=%d: %s\n", __LINE__, ncmpi_strerror(err));nerrs++;}}
60
61 static void
usage(char * argv0)62 usage(char *argv0)
63 {
64 char *help =
65 "Usage: %s [-h] | [-q] [file_name]\n"
66 " [-h] Print help\n"
67 " [-q] Quiet mode (reports when fail)\n"
68 " [filename] output netCDF file name\n";
69 fprintf(stderr, help, argv0);
70 }
71
main(int argc,char ** argv)72 int main(int argc, char** argv)
73 {
74 extern int optind;
75 char filename[256];
76 int i, j, rank, nprocs, verbose=1, err, nerrs=0;
77 int ncid, cmode, varid, dimid[2], num_reqs, *buffer;
78 MPI_Offset w_len, **starts=NULL, **counts=NULL;
79
80 MPI_Init(&argc, &argv);
81 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
82 MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
83
84 /* get command-line arguments */
85 while ((i = getopt(argc, argv, "hq")) != EOF)
86 switch(i) {
87 case 'q': verbose = 0;
88 break;
89 case 'h':
90 default: if (rank==0) usage(argv[0]);
91 MPI_Finalize();
92 return 0;
93 }
94 argc -= optind;
95 argv += optind;
96 if (argc == 1) snprintf(filename, 256, "%s", argv[0]);
97 else strcpy(filename, "testfile.nc");
98
99 if (nprocs != 4 && rank == 0 && verbose)
100 printf("Warning: this program is intended to run on 4 processes\n");
101
102 /* create a new file for writing ----------------------------------------*/
103 cmode = NC_CLOBBER | NC_64BIT_DATA;
104 err = ncmpi_create(MPI_COMM_WORLD, filename, cmode, MPI_INFO_NULL, &ncid);
105 ERR
106
107 /* create a global array of size NY * NX */
108 err = ncmpi_def_dim(ncid, "Y", NY, &dimid[0]);
109 ERR
110 err = ncmpi_def_dim(ncid, "X", NX, &dimid[1]);
111 ERR
112 err = ncmpi_def_var(ncid, "var", NC_INT, NDIMS, dimid, &varid);
113 ERR
114 err = ncmpi_enddef(ncid);
115 ERR
116
117 /* pick arbitrary numbers of requests for 4 processes */
118 num_reqs = 0;
119 if (rank == 0) num_reqs = 4;
120 else if (rank == 1) num_reqs = 6;
121 else if (rank == 2) num_reqs = 5;
122 else if (rank == 3) num_reqs = 4;
123
124 if (num_reqs > 0) {
125 starts = (MPI_Offset**) malloc(num_reqs* sizeof(MPI_Offset*));
126 counts = (MPI_Offset**) malloc(num_reqs* sizeof(MPI_Offset*));
127 starts[0] = (MPI_Offset*) calloc(num_reqs*NDIMS, sizeof(MPI_Offset));
128 counts[0] = (MPI_Offset*) calloc(num_reqs*NDIMS, sizeof(MPI_Offset));
129 for (i=1; i<num_reqs; i++) {
130 starts[i] = starts[i-1] + NDIMS;
131 counts[i] = counts[i-1] + NDIMS;
132 }
133 }
134
135 /* assign arbitrary starts and counts */
136 const int y=0, x=1;
137 if (rank == 0) {
138 starts[0][y] = 0; starts[0][x] = 5; counts[0][y] = 1; counts[0][x] = 2;
139 starts[1][y] = 1; starts[1][x] = 0; counts[1][y] = 1; counts[1][x] = 1;
140 starts[2][y] = 2; starts[2][x] = 6; counts[2][y] = 1; counts[2][x] = 2;
141 starts[3][y] = 3; starts[3][x] = 0; counts[3][y] = 1; counts[3][x] = 3;
142 /* rank 0 is writing the followings: ("-" means skip)
143 - - - - - 0 0 - - -
144 0 - - - - - - - - -
145 - - - - - - 0 0 - -
146 0 0 0 - - - - - - -
147 */
148 } else if (rank ==1) {
149 starts[0][y] = 0; starts[0][x] = 3; counts[0][y] = 1; counts[0][x] = 2;
150 starts[1][y] = 0; starts[1][x] = 8; counts[1][y] = 1; counts[1][x] = 2;
151 starts[2][y] = 1; starts[2][x] = 5; counts[2][y] = 1; counts[2][x] = 2;
152 starts[3][y] = 2; starts[3][x] = 0; counts[3][y] = 1; counts[3][x] = 2;
153 starts[4][y] = 2; starts[4][x] = 8; counts[4][y] = 1; counts[4][x] = 2;
154 starts[5][y] = 3; starts[5][x] = 4; counts[5][y] = 1; counts[5][x] = 3;
155 /* rank 1 is writing the followings: ("-" means skip)
156 - - - 1 1 - - - 1 1
157 - - - - - 1 1 - - -
158 1 1 - - - - - - 1 1
159 - - - - 1 1 1 - - -
160 */
161 } else if (rank ==2) {
162 starts[0][y] = 0; starts[0][x] = 7; counts[0][y] = 1; counts[0][x] = 1;
163 starts[1][y] = 1; starts[1][x] = 1; counts[1][y] = 1; counts[1][x] = 3;
164 starts[2][y] = 1; starts[2][x] = 7; counts[2][y] = 1; counts[2][x] = 3;
165 starts[3][y] = 2; starts[3][x] = 2; counts[3][y] = 1; counts[3][x] = 1;
166 starts[4][y] = 3; starts[4][x] = 3; counts[4][y] = 1; counts[4][x] = 1;
167 /* rank 2 is writing the followings: ("-" means skip)
168 - - - - - - - 2 - -
169 - 2 2 2 - - - 2 2 2
170 - - 2 - - - - - - -
171 - - - 2 - - - - - -
172 */
173 } else if (rank ==3) {
174 starts[0][y] = 0; starts[0][x] = 0; counts[0][y] = 1; counts[0][x] = 3;
175 starts[1][y] = 1; starts[1][x] = 4; counts[1][y] = 1; counts[1][x] = 1;
176 starts[2][y] = 2; starts[2][x] = 3; counts[2][y] = 1; counts[2][x] = 3;
177 starts[3][y] = 3; starts[3][x] = 7; counts[3][y] = 1; counts[3][x] = 3;
178 /* rank 3 is writing the followings: ("-" means skip)
179 3 3 3 - - - - - - -
180 - - - - 3 - - - - -
181 - - - 3 3 3 - - - -
182 - - - - - - - 3 3 3
183 */
184 }
185
186 w_len = 0; /* total write length for this process */
187 for (i=0; i<num_reqs; i++) {
188 MPI_Offset w_req_len=1;
189 for (j=0; j<NDIMS; j++)
190 w_req_len *= counts[i][j];
191 w_len += w_req_len;
192 }
193
194 /* allocate I/O buffer and initialize its contents */
195 buffer = (int*) malloc(w_len * sizeof(int));
196 for (i=0; i<w_len; i++) buffer[i] = rank;
197
198 /* set the buffer pointers to different offsets to the I/O buffer */
199 err = ncmpi_put_varn_int_all(ncid, varid, num_reqs, starts,
200 counts, buffer);
201 ERR
202
203 err = ncmpi_close(ncid);
204 ERR
205
206 free(buffer);
207 if (num_reqs > 0) {
208 free(starts[0]);
209 free(counts[0]);
210 free(starts);
211 free(counts);
212 }
213
214 /* check if there is any PnetCDF internal malloc residue */
215 MPI_Offset malloc_size, sum_size;
216 err = ncmpi_inq_malloc_size(&malloc_size);
217 if (err == NC_NOERR) {
218 MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD);
219 if (rank == 0 && sum_size > 0)
220 printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n",
221 sum_size);
222 }
223
224 MPI_Finalize();
225 return nerrs;
226 }
227
228