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