1dnl Process this m4 file to produce 'C' language file. 2dnl 3dnl If you see this line, you can ignore the next one. 4/* Do not edit this file. It is produced from the corresponding .m4 source */ 5dnl 6/* 7 * Copyright (C) 2014, Northwestern University and Argonne National Laboratory 8 * See COPYRIGHT notice in top-level directory. 9 */ 10/* $Id: varn.m4 2695 2016-12-10 17:02:11Z wkliao $ */ 11 12#if HAVE_CONFIG_H 13# include <ncconfig.h> 14#endif 15 16#include <stdio.h> 17#include <unistd.h> 18#ifdef HAVE_STDLIB_H 19#include <stdlib.h> 20#endif 21#include <assert.h> 22 23#include <mpi.h> 24 25#include "nc.h" 26#include "ncx.h" 27#include "ncmpidtype.h" 28#include "macro.h" 29 30include(`foreach.m4') 31include(`utils.m4') 32 33/* ncmpi_get/put_varn_<type>_<mode> API: 34 * type: data type of I/O buffer, buf 35 * mode: independent (<nond>) or collective (_all) 36 * 37 * arguments: 38 * num: number of start and count pairs 39 * starts: an 2D array of size [num][ndims]. Each starts[i][*] indicates 40 * the starting array indices for a subarray request. ndims is 41 * the number of dimensions of the defined netCDF variable. 42 * counts: an 2D array of size [num][ndims]. Each counts[i][*] indicates 43 * the number of array elements to be accessed. This argument 44 * can be NULL, equivalent to counts with all 1s. 45 * bufcount and buftype: these 2 arguments are only available for flexible 46 * APIs, indicating the I/O buffer memory layout. When buftype is 47 * MPI_DATATYPE_NULL, bufcount is ignored and the data type of buf 48 * is considered matched the variable data type defined in the file. 49 */ 50 51static int 52ncmpii_getput_varn(NC *ncp, 53 NC_var *varp, 54 int num, 55 MPI_Offset* const *starts, /* [num][varp->ndims] */ 56 MPI_Offset* const *counts, /* [num][varp->ndims] */ 57 void *buf, 58 MPI_Offset bufcount, 59 MPI_Datatype buftype, /* data type of the buffer */ 60 int rw_flag, 61 int io_method); 62 63define(`BufConst', `ifelse(`$1', `put', `const')')dnl 64 65dnl 66dnl VARN_FLEXIBLE(ncid, varid, num starts, counts, buf, bufcount, buftype) 67dnl 68define(`VARN_FLEXIBLE',dnl 69`dnl 70/*----< ncmpi_$1_varn$2() >---------------------------------------------------*/ 71int 72ncmpi_$1_varn$2(int ncid, 73 int varid, 74 int num, 75 MPI_Offset* const *starts, 76 MPI_Offset* const *counts, 77 BufConst($1) void *buf, 78 MPI_Offset bufcount, 79 MPI_Datatype buftype) 80{ 81 int err, status; 82 NC *ncp; 83 NC_var *varp=NULL; 84 85 status = ncmpii_sanity_check(ncid, varid, NULL, NULL, NULL, bufcount, 86 buftype, API_VARN, 1, 1, ReadWrite($1), 87 CollIndep($2), &ncp, &varp); 88 if (status != NC_NOERR) { 89 if (CollIndep($2) == INDEP_IO || 90 status == NC_EBADID || 91 status == NC_EPERM || 92 status == NC_EINDEFINE || 93 status == NC_EINDEP || 94 status == NC_ENOTINDEP) 95 return status; /* fatal error, cannot continue */ 96 97 /* for collective API, participate the collective I/O with zero-length 98 * request for this process */ 99 err = ncmpii_getput_zero_req(ncp, ReadWrite($1)); 100 assert(err == NC_NOERR); 101 102 /* return the error code from sanity check */ 103 return status; 104 } 105 106 return ncmpii_getput_varn(ncp, varp, num, starts, counts, (void*)buf, 107 bufcount, buftype, ReadWrite($1), CollIndep($2)); 108} 109')dnl 110 111dnl PnetCDF flexible APIs 112VARN_FLEXIBLE(put) 113VARN_FLEXIBLE(put, _all) 114VARN_FLEXIBLE(get) 115VARN_FLEXIBLE(get, _all) 116 117dnl 118dnl VARN(ncid, varid, starts, counts, buf) 119dnl 120define(`VARN',dnl 121`dnl 122/*----< ncmpi_$1_varn_$3$2() >------------------------------------------------*/ 123int 124ncmpi_$1_varn_$3$2(int ncid, 125 int varid, 126 int num, 127 MPI_Offset* const *starts, 128 MPI_Offset* const *counts, 129 BufConst($1) $4 *buf) 130{ 131 int err, status; 132 NC *ncp; 133 NC_var *varp=NULL; 134 135 status = ncmpii_sanity_check(ncid, varid, NULL, NULL, NULL, 0, 136 ITYPE2MPI($3), API_VARN, 0, 1, ReadWrite($1), 137 CollIndep($2), &ncp, &varp); 138 if (status != NC_NOERR) { 139 if (CollIndep($2) == INDEP_IO || 140 status == NC_EBADID || 141 status == NC_EPERM || 142 status == NC_EINDEFINE || 143 status == NC_EINDEP || 144 status == NC_ENOTINDEP) 145 return status; /* fatal error, cannot continue */ 146 147 /* for collective API, participate the collective I/O with zero-length 148 * request for this process */ 149 err = ncmpii_getput_zero_req(ncp, ReadWrite($1)); 150 assert(err == NC_NOERR); 151 152 /* return the error code from sanity check */ 153 return status; 154 } 155 156 /* set bufcount to -1 indicating non-flexible API */ 157 return ncmpii_getput_varn(ncp, varp, num, starts, counts, (void*)buf, 158 -1, $5, ReadWrite($1), CollIndep($2)); 159} 160')dnl 161dnl 162foreach(`putget', (put, get), 163 `foreach(`collindep', (, _all), 164 `foreach(`itype', (ITYPE_LIST), 165 `VARN(putget,collindep,itype,FUNC2ITYPE(itype),ITYPE2MPI(itype)) 166')')') 167 168/*----< ncmpii_getput_varn() >------------------------------------------------*/ 169static int 170ncmpii_getput_varn(NC *ncp, 171 NC_var *varp, 172 int num, 173 MPI_Offset* const *starts, /* [num][varp->ndims] */ 174 MPI_Offset* const *counts, /* [num][varp->ndims] */ 175 void *buf, 176 MPI_Offset bufcount, 177 MPI_Datatype buftype, /* data type of the buffer */ 178 int rw_flag, /* WRITE_REQ or READ_REQ */ 179 int io_method) /* COLL_IO or INDEP_IO */ 180{ 181 int i, j, el_size, status=NC_NOERR, min_st, err, free_cbuf=0; 182 int req_id=NC_REQ_NULL, st, isSameGroup, position; 183 void *cbuf=NULL; 184 char *bufp; 185 MPI_Offset packsize=0, **_counts=NULL; 186 MPI_Datatype ptype; 187 188 /* check for zero-size request */ 189 if (num == 0 || bufcount == 0) goto err_check; 190 191 /* it is illegal for starts to be NULL */ 192 if (starts == NULL) { 193 DEBUG_ASSIGN_ERROR(status, NC_ENULLSTART) 194 goto err_check; 195 } 196 else { /* it is illegal for any starts[i] to be NULL */ 197 for (i=0; i<num; i++) { 198 if (starts[i] == NULL) { 199 DEBUG_ASSIGN_ERROR(status, NC_ENULLSTART) 200 goto err_check; 201 } 202 } 203 } 204 205 if (buftype == MPI_DATATYPE_NULL) { 206 /* In this case, bufcount is ignored and will be recalculated to match 207 * counts[]. Note buf's data type must match the data type of 208 * variable defined in the file - no data conversion will be done. 209 */ 210 if (counts == NULL) 211 bufcount = 1; 212 else { 213 bufcount = 0; 214 for (j=0; j<num; j++) { 215 MPI_Offset bufcount_j = 1; 216 if (counts[i] == NULL) { 217 DEBUG_ASSIGN_ERROR(status, NC_ENULLCOUNT) 218 goto err_check; 219 } 220 for (i=0; i<varp->ndims; i++) { 221 if (counts[j][i] < 0) { /* no negative counts[][] */ 222 DEBUG_ASSIGN_ERROR(status, NC_ENEGATIVECNT) 223 goto err_check; 224 } 225 bufcount_j *= counts[j][i]; 226 } 227 bufcount += bufcount_j; 228 } 229 } 230 /* assign buftype match with the variable's data type */ 231 buftype = ncmpii_nc2mpitype(varp->type); 232 } 233 234 cbuf = buf; 235 if (bufcount > 0) { /* flexible API is used */ 236 /* pack buf into cbuf, a contiguous buffer */ 237 int isderived, iscontig_of_ptypes; 238 MPI_Offset bnelems=0; 239 240 /* ptype (primitive MPI data type) from buftype 241 * el_size is the element size of ptype 242 * bnelems is the total number of ptype elements in buftype 243 */ 244 status = ncmpii_dtype_decode(buftype, &ptype, &el_size, &bnelems, 245 &isderived, &iscontig_of_ptypes); 246 247 if (status != NC_NOERR) goto err_check; 248 249 if (bufcount != (int)bufcount) { 250 DEBUG_ASSIGN_ERROR(status, NC_EINTOVERFLOW) 251 goto err_check; 252 } 253 254 /* check if buftype is contiguous, if not, pack to one, cbuf */ 255 if (! iscontig_of_ptypes && bnelems > 0) { 256 position = 0; 257 packsize = bnelems*el_size; 258 if (packsize != (int)packsize) { 259 DEBUG_ASSIGN_ERROR(status, NC_EINTOVERFLOW) 260 goto err_check; 261 } 262 cbuf = NCI_Malloc((size_t)packsize); 263 free_cbuf = 1; 264 if (rw_flag == WRITE_REQ) 265 MPI_Pack(buf, (int)bufcount, buftype, cbuf, (int)packsize, 266 &position, MPI_COMM_SELF); 267 } 268 } 269 else { 270 /* this subroutine is called from a high-level API */ 271 status = NCMPII_ECHAR(varp->type, buftype); 272 if (status != NC_NOERR) goto err_check; 273 274 ptype = buftype; 275 el_size = ncmpix_len_nctype(varp->type); 276 } 277 278 /* We allow counts == NULL and treat this the same as all 1s */ 279 if (counts == NULL) { 280 _counts = (MPI_Offset**) NCI_Malloc((size_t)num * sizeof(MPI_Offset*)); 281 _counts[0] = (MPI_Offset*) NCI_Malloc((size_t)(num * varp->ndims * 282 SIZEOF_MPI_OFFSET)); 283 for (i=1; i<num; i++) 284 _counts[i] = _counts[i-1] + varp->ndims; 285 for (i=0; i<num; i++) 286 for (j=0; j<varp->ndims; j++) 287 _counts[i][j] = 1; 288 } 289 else 290 _counts = (MPI_Offset**) counts; 291 292 /* break buf into num pieces */ 293 isSameGroup=0; 294 bufp = (char*)cbuf; 295 for (i=0; i<num; i++) { 296 MPI_Offset buflen; 297 for (buflen=1, j=0; j<varp->ndims; j++) { 298 if (_counts[i][j] < 0) { /* any negative counts[][] is illegal */ 299 DEBUG_ASSIGN_ERROR(status, NC_ENEGATIVECNT) 300 goto err_check; 301 } 302 buflen *= _counts[i][j]; 303 } 304 if (buflen == 0) continue; 305 status = ncmpii_igetput_varm(ncp, varp, starts[i], _counts[i], NULL, 306 NULL, bufp, buflen, ptype, &req_id, 307 rw_flag, 0, isSameGroup); 308 if (status != NC_NOERR) goto err_check; 309 310 /* use isSamegroup so we end up with one nonblocking request (only the 311 * first request gets a request ID back, the rest reuse the same ID. 312 * This single ID represents num nonblocking requests */ 313 isSameGroup=1; 314 bufp += buflen * el_size; 315 } 316 317err_check: 318 if (_counts != NULL && _counts != counts) { 319 NCI_Free(_counts[0]); 320 NCI_Free(_counts); 321 } 322 323 if (ncp->safe_mode == 1 && io_method == COLL_IO) { 324 int mpireturn; 325 TRACE_COMM(MPI_Allreduce)(&status, &min_st, 1, MPI_INT, MPI_MIN, 326 ncp->nciop->comm); 327 if (mpireturn != MPI_SUCCESS) 328 return ncmpii_handle_error(mpireturn, "MPI_Allreduce"); 329 330 if (min_st != NC_NOERR) { 331 if (req_id != NC_REQ_NULL) /* cancel pending nonblocking request */ 332 ncmpii_cancel(ncp, 1, &req_id, &st); 333 if (free_cbuf) NCI_Free(cbuf); 334 return status; 335 } 336 } 337 338 if (io_method == INDEP_IO && status != NC_NOERR) { 339 if (req_id != NC_REQ_NULL) /* cancel pending nonblocking request */ 340 ncmpii_cancel(ncp, 1, &req_id, &st); 341 if (free_cbuf) NCI_Free(cbuf); 342 return status; 343 } 344 345 num = 1; 346 if (status != NC_NOERR) 347 /* This can only be reached for COLL_IO and safe_mode == 0. 348 Set num=0 just so this process can participate the collective 349 calls in wait_all */ 350 num = 0; 351 352 err = ncmpii_wait(ncp, io_method, num, &req_id, &st); 353 354 /* unpack to user buf, if buftype is noncontiguous */ 355 if (status == NC_NOERR && rw_flag == READ_REQ && free_cbuf) { 356 position = 0; 357 MPI_Unpack(cbuf, (int)packsize, &position, buf, (int)bufcount, buftype, 358 MPI_COMM_SELF); 359 } 360 361 /* return the first error, if there is one */ 362 if (status == NC_NOERR) status = err; 363 if (status == NC_NOERR) status = st; 364 365 if (free_cbuf) NCI_Free(cbuf); 366 367 return status; 368} 369