Actual source code: sysio.c

  1: /*
  2:    This file contains simple binary read/write routines.
  3:  */

  5: #include <petscsys.h>
  6: #include <petscbt.h>
  7: #include <errno.h>
  8: #include <fcntl.h>
  9: #if defined(PETSC_HAVE_UNISTD_H)
 10:   #include <unistd.h>
 11: #endif
 12: #if defined(PETSC_HAVE_IO_H)
 13:   #include <io.h>
 14: #endif
 15: #if !defined(PETSC_HAVE_O_BINARY)
 16:   #define O_BINARY 0
 17: #endif

 19: const char *const PetscFileModes[] = {"READ", "WRITE", "APPEND", "UPDATE", "APPEND_UPDATE", "PetscFileMode", "PETSC_FILE_", NULL};

 21: /*
 22:   PetscByteSwapEnum - Swap bytes in a  PETSc Enum

 24: */
 25: static PetscErrorCode PetscByteSwapEnum(PetscEnum *buff, PetscInt n)
 26: {
 27:   PetscInt  i, j;
 28:   PetscEnum tmp = ENUM_DUMMY;
 29:   char     *ptr1, *ptr2 = (char *)&tmp;

 31:   PetscFunctionBegin;
 32:   for (j = 0; j < n; j++) {
 33:     ptr1 = (char *)(buff + j);
 34:     for (i = 0; i < (PetscInt)sizeof(PetscEnum); i++) ptr2[i] = ptr1[sizeof(PetscEnum) - 1 - i];
 35:     for (i = 0; i < (PetscInt)sizeof(PetscEnum); i++) ptr1[i] = ptr2[i];
 36:   }
 37:   PetscFunctionReturn(PETSC_SUCCESS);
 38: }

 40: /*
 41:   PetscByteSwapBool - Swap bytes in a  PETSc Bool

 43: */
 44: static PetscErrorCode PetscByteSwapBool(PetscBool *buff, PetscInt n)
 45: {
 46:   PetscInt  i, j;
 47:   PetscBool tmp = PETSC_FALSE;
 48:   char     *ptr1, *ptr2 = (char *)&tmp;

 50:   PetscFunctionBegin;
 51:   for (j = 0; j < n; j++) {
 52:     ptr1 = (char *)(buff + j);
 53:     for (i = 0; i < (PetscInt)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool) - 1 - i];
 54:     for (i = 0; i < (PetscInt)sizeof(PetscBool); i++) ptr1[i] = ptr2[i];
 55:   }
 56:   PetscFunctionReturn(PETSC_SUCCESS);
 57: }

 59: /*
 60:   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64-bits)

 62: */
 63: static PetscErrorCode PetscByteSwapInt(PetscInt *buff, PetscInt n)
 64: {
 65:   PetscInt i, j, tmp = 0;
 66:   char    *ptr1, *ptr2 = (char *)&tmp;

 68:   PetscFunctionBegin;
 69:   for (j = 0; j < n; j++) {
 70:     ptr1 = (char *)(buff + j);
 71:     for (i = 0; i < (PetscInt)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt) - 1 - i];
 72:     for (i = 0; i < (PetscInt)sizeof(PetscInt); i++) ptr1[i] = ptr2[i];
 73:   }
 74:   PetscFunctionReturn(PETSC_SUCCESS);
 75: }

 77: /*
 78:   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64-bits)

 80: */
 81: static PetscErrorCode PetscByteSwapInt64(PetscInt64 *buff, PetscInt n)
 82: {
 83:   PetscInt   i, j;
 84:   PetscInt64 tmp = 0;
 85:   char      *ptr1, *ptr2 = (char *)&tmp;

 87:   PetscFunctionBegin;
 88:   for (j = 0; j < n; j++) {
 89:     ptr1 = (char *)(buff + j);
 90:     for (i = 0; i < (PetscInt)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64) - 1 - i];
 91:     for (i = 0; i < (PetscInt)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i];
 92:   }
 93:   PetscFunctionReturn(PETSC_SUCCESS);
 94: }

 96: /*
 97:   PetscByteSwapInt32 - Swap bytes in a  PETSc integer (32-bits)

 99: */
100: static PetscErrorCode PetscByteSwapInt32(PetscInt32 *buff, PetscInt n)
101: {
102:   PetscInt   i, j;
103:   PetscInt32 tmp = 0;
104:   char      *ptr1, *ptr2 = (char *)&tmp;

106:   PetscFunctionBegin;
107:   for (j = 0; j < n; j++) {
108:     ptr1 = (char *)(buff + j);
109:     for (i = 0; i < (PetscInt)sizeof(PetscInt32); i++) ptr2[i] = ptr1[sizeof(PetscInt32) - 1 - i];
110:     for (i = 0; i < (PetscInt)sizeof(PetscInt32); i++) ptr1[i] = ptr2[i];
111:   }
112:   PetscFunctionReturn(PETSC_SUCCESS);
113: }

115: /*
116:   PetscByteSwapShort - Swap bytes in a short
117: */
118: static PetscErrorCode PetscByteSwapShort(short *buff, PetscInt n)
119: {
120:   PetscInt i, j;
121:   short    tmp;
122:   char    *ptr1, *ptr2 = (char *)&tmp;

124:   PetscFunctionBegin;
125:   for (j = 0; j < n; j++) {
126:     ptr1 = (char *)(buff + j);
127:     for (i = 0; i < (PetscInt)sizeof(short); i++) ptr2[i] = ptr1[sizeof(short) - 1 - i];
128:     for (i = 0; i < (PetscInt)sizeof(short); i++) ptr1[i] = ptr2[i];
129:   }
130:   PetscFunctionReturn(PETSC_SUCCESS);
131: }
132: /*
133:   PetscByteSwapLong - Swap bytes in a long
134: */
135: static PetscErrorCode PetscByteSwapLong(long *buff, PetscInt n)
136: {
137:   PetscInt i, j;
138:   long     tmp;
139:   char    *ptr1, *ptr2 = (char *)&tmp;

141:   PetscFunctionBegin;
142:   for (j = 0; j < n; j++) {
143:     ptr1 = (char *)(buff + j);
144:     for (i = 0; i < (PetscInt)sizeof(long); i++) ptr2[i] = ptr1[sizeof(long) - 1 - i];
145:     for (i = 0; i < (PetscInt)sizeof(long); i++) ptr1[i] = ptr2[i];
146:   }
147:   PetscFunctionReturn(PETSC_SUCCESS);
148: }

150: /*
151:   PetscByteSwapReal - Swap bytes in a PetscReal
152: */
153: static PetscErrorCode PetscByteSwapReal(PetscReal *buff, PetscInt n)
154: {
155:   PetscInt  i, j;
156:   PetscReal tmp, *buff1 = (PetscReal *)buff;
157:   char     *ptr1, *ptr2 = (char *)&tmp;

159:   PetscFunctionBegin;
160:   for (j = 0; j < n; j++) {
161:     ptr1 = (char *)(buff1 + j);
162:     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i];
163:     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
164:   }
165:   PetscFunctionReturn(PETSC_SUCCESS);
166: }

168: /*
169:   PetscByteSwapScalar - Swap bytes in a PetscScalar
170:   The complex case is dealt with with an array of PetscReal, twice as long.
171: */
172: static PetscErrorCode PetscByteSwapScalar(PetscScalar *buff, PetscInt n)
173: {
174:   PetscInt  i, j;
175:   PetscReal tmp, *buff1 = (PetscReal *)buff;
176:   char     *ptr1, *ptr2 = (char *)&tmp;

178:   PetscFunctionBegin;
179: #if defined(PETSC_USE_COMPLEX)
180:   n *= 2;
181: #endif
182:   for (j = 0; j < n; j++) {
183:     ptr1 = (char *)(buff1 + j);
184:     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i];
185:     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
186:   }
187:   PetscFunctionReturn(PETSC_SUCCESS);
188: }

190: /*
191:   PetscByteSwapDouble - Swap bytes in a double
192: */
193: static PetscErrorCode PetscByteSwapDouble(double *buff, PetscInt n)
194: {
195:   PetscInt i, j;
196:   double   tmp, *buff1 = (double *)buff;
197:   char    *ptr1, *ptr2 = (char *)&tmp;

199:   PetscFunctionBegin;
200:   for (j = 0; j < n; j++) {
201:     ptr1 = (char *)(buff1 + j);
202:     for (i = 0; i < (PetscInt)sizeof(double); i++) ptr2[i] = ptr1[sizeof(double) - 1 - i];
203:     for (i = 0; i < (PetscInt)sizeof(double); i++) ptr1[i] = ptr2[i];
204:   }
205:   PetscFunctionReturn(PETSC_SUCCESS);
206: }

208: /*
209:   PetscByteSwapFloat - Swap bytes in a float
210: */
211: static PetscErrorCode PetscByteSwapFloat(float *buff, PetscInt n)
212: {
213:   PetscInt i, j;
214:   float    tmp, *buff1 = (float *)buff;
215:   char    *ptr1, *ptr2 = (char *)&tmp;

217:   PetscFunctionBegin;
218:   for (j = 0; j < n; j++) {
219:     ptr1 = (char *)(buff1 + j);
220:     for (i = 0; i < (PetscInt)sizeof(float); i++) ptr2[i] = ptr1[sizeof(float) - 1 - i];
221:     for (i = 0; i < (PetscInt)sizeof(float); i++) ptr1[i] = ptr2[i];
222:   }
223:   PetscFunctionReturn(PETSC_SUCCESS);
224: }

226: PetscErrorCode PetscByteSwap(void *data, PetscDataType pdtype, PetscInt count)
227: {
228:   PetscFunctionBegin;
229:   if (pdtype == PETSC_INT) PetscCall(PetscByteSwapInt((PetscInt *)data, count));
230:   else if (pdtype == PETSC_ENUM) PetscCall(PetscByteSwapEnum((PetscEnum *)data, count));
231:   else if (pdtype == PETSC_BOOL) PetscCall(PetscByteSwapBool((PetscBool *)data, count));
232:   else if (pdtype == PETSC_SCALAR) PetscCall(PetscByteSwapScalar((PetscScalar *)data, count));
233:   else if (pdtype == PETSC_REAL) PetscCall(PetscByteSwapReal((PetscReal *)data, count));
234:   else if (pdtype == PETSC_COMPLEX) PetscCall(PetscByteSwapReal((PetscReal *)data, 2 * count));
235:   else if (pdtype == PETSC_INT64) PetscCall(PetscByteSwapInt64((PetscInt64 *)data, count));
236:   else if (pdtype == PETSC_INT32) PetscCall(PetscByteSwapInt32((PetscInt32 *)data, count));
237:   else if (pdtype == PETSC_DOUBLE) PetscCall(PetscByteSwapDouble((double *)data, count));
238:   else if (pdtype == PETSC_FLOAT) PetscCall(PetscByteSwapFloat((float *)data, count));
239:   else if (pdtype == PETSC_SHORT) PetscCall(PetscByteSwapShort((short *)data, count));
240:   else if (pdtype == PETSC_LONG) PetscCall(PetscByteSwapLong((long *)data, count));
241:   else if (pdtype == PETSC_CHAR) PetscFunctionReturn(PETSC_SUCCESS);
242:   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown type: %d", pdtype);
243:   PetscFunctionReturn(PETSC_SUCCESS);
244: }

246: /*@C
247:   PetscBinaryRead - Reads from a binary file.

249:   Not Collective

251:   Input Parameters:
252: + fd   - the file descriptor
253: . num  - the maximum number of items to read
254: - type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)

256:   Output Parameters:
257: + data  - the buffer, this is an array of the type that matches the value in `type`
258: - count - the number of items read, optional

260:   Level: developer

262:   Notes:
263:   If `count` is not provided and the number of items read is less than
264:   the maximum number of items to read, then this routine errors.

266:   `PetscBinaryRead()` uses byte swapping to work on all machines; the files
267:   are written ALWAYS using big-endian ordering. On little-endian machines the numbers
268:   are converted to the little-endian format when they are read in from the file.
269:   When PETSc is ./configure with `--with-64-bit-indices` the integers are written to the
270:   file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices`
271:   is used.

273: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
274:           `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
275: @*/
276: PetscErrorCode PetscBinaryRead(int fd, void *data, PetscInt num, PetscInt *count, PetscDataType type)
277: {
278:   size_t typesize, m = (size_t)num, n = 0, maxblock = 65536;
279:   char  *p = (char *)data;
280: #if defined(PETSC_USE_REAL___FLOAT128)
281:   PetscBool readdouble = PETSC_FALSE;
282:   double   *pdouble;
283: #endif
284:   void *ptmp  = data;
285:   char *fname = NULL;

287:   PetscFunctionBegin;
288:   if (count) *count = 0;
289:   PetscCheck(num >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to read a negative amount of data %" PetscInt_FMT, num);
290:   if (!num) PetscFunctionReturn(PETSC_SUCCESS);

292:   if (type == PETSC_FUNCTION) {
293:     m     = 64;
294:     type  = PETSC_CHAR;
295:     fname = (char *)malloc(m * sizeof(char));
296:     p     = (char *)fname;
297:     ptmp  = (void *)fname;
298:     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
299:   }
300:   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m);

302:   PetscCall(PetscDataTypeGetSize(type, &typesize));

304: #if defined(PETSC_USE_REAL___FLOAT128)
305:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-binary_read_double", &readdouble, NULL));
306:   /* If using __float128 precision we still read in doubles from file */
307:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
308:     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
309:     PetscCall(PetscMalloc1(cnt, &pdouble));
310:     p = (char *)pdouble;
311:     typesize /= 2;
312:   }
313: #endif

315:   m *= typesize;

317:   while (m) {
318:     size_t len = (m < maxblock) ? m : maxblock;
319:     int    ret = (int)read(fd, p, len);
320:     if (ret < 0 && errno == EINTR) continue;
321:     if (!ret && len > 0) break; /* Proxy for EOF */
322:     PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file due to \"%s\"", strerror(errno));
323:     m -= (size_t)ret;
324:     p += ret;
325:     n += (size_t)ret;
326:   }
327:   PetscCheck(!m || count, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Read past end of file");

329:   num = (PetscInt)(n / typesize); /* Should we require `n % typesize == 0` ? */
330:   if (count) *count = num;        /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */

332: #if defined(PETSC_USE_REAL___FLOAT128)
333:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
334:     PetscInt   i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
335:     PetscReal *preal = (PetscReal *)data;
336:     if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwapDouble(pdouble, cnt));
337:     for (i = 0; i < cnt; i++) preal[i] = pdouble[i];
338:     PetscCall(PetscFree(pdouble));
339:     PetscFunctionReturn(PETSC_SUCCESS);
340:   }
341: #endif

343:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(ptmp, type, num));

345:   if (type == PETSC_FUNCTION) {
346: #if defined(PETSC_SERIALIZE_FUNCTIONS)
347:     PetscCall(PetscDLSym(NULL, fname, (void **)data));
348: #else
349:     *(void **)data = NULL;
350: #endif
351:     free(fname);
352:   }
353:   PetscFunctionReturn(PETSC_SUCCESS);
354: }

356: /*@C
357:   PetscBinaryWrite - Writes to a binary file.

359:   Not Collective

361:   Input Parameters:
362: + fd   - the file
363: . p    - the buffer, an array of the type that matches the value in `type`
364: . n    - the number of items to write
365: - type - the type of items to read (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

367:   Level: advanced

369:   Notes:
370:   `PetscBinaryWrite()` uses byte swapping to work on all machines; the files
371:   are written using big-endian ordering to the file. On little-endian machines the numbers
372:   are converted to the big-endian format when they are written to disk.
373:   When PETSc is configured using `./configure with --with-64-bit-indices` the integers are written to the
374:   file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices`
375:   is used.

377:   If running with `__float128` precision the output of `PETSC_REAL` is in `__float128` unless one uses the `-binary_write_double` option

379:   The buffer `p` should be read-write buffer, and not static data.
380:   This way, byte-swapping is done in-place, and then the buffer is
381:   written to the file.

383:   This routine restores the original contents of the buffer, after
384:   it is written to the file. This is done by byte-swapping in-place
385:   the second time.

387:   Because byte-swapping may be done on the values in data it cannot be declared const

389: .seealso: `PetscBinaryRead()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
390:           `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
391: @*/
392: PetscErrorCode PetscBinaryWrite(int fd, const void *p, PetscInt n, PetscDataType type)
393: {
394:   const char *pp = (char *)p;
395:   int         err, wsize;
396:   size_t      m = (size_t)n, maxblock = 65536;
397:   const void *ptmp  = p;
398:   char       *fname = NULL;
399: #if defined(PETSC_USE_REAL___FLOAT128)
400:   PetscBool  writedouble = PETSC_FALSE;
401:   double    *ppp;
402:   PetscReal *pv;
403:   PetscInt   i;
404: #endif
405:   PetscDataType wtype = type;

407:   PetscFunctionBegin;
408:   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to write a negative amount of data %" PetscInt_FMT, n);
409:   if (!n) PetscFunctionReturn(PETSC_SUCCESS);

411:   if (type == PETSC_FUNCTION) {
412: #if defined(PETSC_SERIALIZE_FUNCTIONS)
413:     const char *fnametmp;
414: #endif
415:     m     = 64;
416:     fname = (char *)malloc(m * sizeof(char));
417:     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
418: #if defined(PETSC_SERIALIZE_FUNCTIONS)
419:     PetscCheck(n <= 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only binary view a single function at a time");
420:     PetscCall(PetscFPTFind(*(void **)p, &fnametmp));
421:     PetscCall(PetscStrncpy(fname, fnametmp, m));
422: #else
423:     PetscCall(PetscStrncpy(fname, "", m));
424: #endif
425:     wtype = PETSC_CHAR;
426:     pp    = (char *)fname;
427:     ptmp  = (void *)fname;
428:   }

430: #if defined(PETSC_USE_REAL___FLOAT128)
431:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-binary_write_double", &writedouble, NULL));
432:   /* If using __float128 precision we still write in doubles to file */
433:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
434:     wtype = PETSC_DOUBLE;
435:     PetscCall(PetscMalloc1(n, &ppp));
436:     pv = (PetscReal *)pp;
437:     for (i = 0; i < n; i++) ppp[i] = (double)pv[i];
438:     pp   = (char *)ppp;
439:     ptmp = (char *)ppp;
440:   }
441: #endif

443:   if (wtype == PETSC_INT) m *= sizeof(PetscInt);
444:   else if (wtype == PETSC_SCALAR) m *= sizeof(PetscScalar);
445: #if defined(PETSC_HAVE_COMPLEX)
446:   else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
447: #endif
448:   else if (wtype == PETSC_REAL) m *= sizeof(PetscReal);
449:   else if (wtype == PETSC_DOUBLE) m *= sizeof(double);
450:   else if (wtype == PETSC_FLOAT) m *= sizeof(float);
451:   else if (wtype == PETSC_SHORT) m *= sizeof(short);
452:   else if (wtype == PETSC_LONG) m *= sizeof(long);
453:   else if (wtype == PETSC_CHAR) m *= sizeof(char);
454:   else if (wtype == PETSC_ENUM) m *= sizeof(PetscEnum);
455:   else if (wtype == PETSC_BOOL) m *= sizeof(PetscBool);
456:   else if (wtype == PETSC_INT64) m *= sizeof(PetscInt64);
457:   else if (wtype == PETSC_INT32) m *= sizeof(PetscInt32);
458:   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m) * sizeof(char);
459:   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown type: %d", wtype);

461:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap((void *)ptmp, wtype, n));

463:   while (m) {
464:     wsize = (m < maxblock) ? m : maxblock;
465:     err   = write(fd, pp, wsize);
466:     if (err < 0 && errno == EINTR) continue;
467:     PetscCheck(err == wsize, PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE, "Error writing to file total size %d err %d wsize %d due to \"%s\"", (int)n, (int)err, (int)wsize, strerror(errno));
468:     m -= wsize;
469:     pp += wsize;
470:   }

472:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap((void *)ptmp, wtype, n));

474:   if (type == PETSC_FUNCTION) free(fname);
475: #if defined(PETSC_USE_REAL___FLOAT128)
476:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) PetscCall(PetscFree(ppp));
477: #endif
478:   PetscFunctionReturn(PETSC_SUCCESS);
479: }

481: /*@C
482:   PetscBinaryOpen - Opens a PETSc binary file.

484:   Not Collective

486:   Input Parameters:
487: + name - filename
488: - mode - open mode of binary file, one of `FILE_MODE_READ`, `FILE_MODE_WRITE`, `FILE_MODE_APPEND`

490:   Output Parameter:
491: . fd - the file

493:   Level: advanced

495: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscFileMode`, `PetscViewerFileSetMode()`, `PetscViewerBinaryGetDescriptor()`,
496:           `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
497: @*/
498: PetscErrorCode PetscBinaryOpen(const char name[], PetscFileMode mode, int *fd)
499: {
500:   PetscFunctionBegin;
501:   switch (mode) {
502:   case FILE_MODE_READ:
503:     *fd = open(name, O_BINARY | O_RDONLY, 0);
504:     break;
505:   case FILE_MODE_WRITE:
506:     *fd = open(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
507:     break;
508:   case FILE_MODE_APPEND:
509:     *fd = open(name, O_BINARY | O_WRONLY | O_APPEND, 0);
510:     break;
511:   default:
512:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[mode]);
513:   }
514:   PetscCheck(*fd != -1, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open file %s for %s due to \"%s\"", name, PetscFileModes[mode], strerror(errno));
515:   PetscFunctionReturn(PETSC_SUCCESS);
516: }

518: /*@
519:   PetscBinaryClose - Closes a PETSc binary file.

521:   Not Collective

523:   Output Parameter:
524: . fd - the file

526:   Level: advanced

528: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
529:           `PetscBinarySynchronizedSeek()`
530: @*/
531: PetscErrorCode PetscBinaryClose(int fd)
532: {
533:   PetscFunctionBegin;
534:   PetscCheck(!close(fd), PETSC_COMM_SELF, PETSC_ERR_SYS, "close() failed on file descriptor");
535:   PetscFunctionReturn(PETSC_SUCCESS);
536: }

538: /*@C
539:   PetscBinarySeek - Moves the file pointer on a PETSc binary file.

541:   Not Collective

543:   Input Parameters:
544: + fd     - the file
545: . off    - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
546:             etc. in your calculation rather than `sizeof()` to compute byte lengths.
547: - whence - see `PetscBinarySeekType` for possible values

549:   Output Parameter:
550: . offset - new offset in file

552:   Level: developer

554: .seealso: `PetscBinaryRead()`, `PetscBinarySeekType`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
555:           `PetscBinarySynchronizedSeek()`
556: @*/
557: PetscErrorCode PetscBinarySeek(int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
558: {
559:   int iwhence = 0;

561:   PetscFunctionBegin;
562:   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
563:   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
564:   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
565:   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown seek location");
566: #if defined(PETSC_HAVE_LSEEK)
567:   *offset = lseek(fd, off, iwhence);
568: #elif defined(PETSC_HAVE__LSEEK)
569:   *offset = _lseek(fd, (long)off, iwhence);
570: #else
571:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "System does not have a way of seeking on a file");
572: #endif
573:   PetscFunctionReturn(PETSC_SUCCESS);
574: }

576: /*@C
577:   PetscBinarySynchronizedRead - Reads from a binary file, all MPI processes get the same values

579:   Collective

581:   Input Parameters:
582: + comm - the MPI communicator
583: . fd   - the file descriptor
584: . num  - the maximum number of items to read
585: - type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)

587:   Output Parameters:
588: + data  - the buffer, an array of the type that matches the value in `type`
589: - count - the number of items read, optional

591:   Level: developer

593:   Notes:
594:   Does a `PetscBinaryRead()` followed by an `MPI_Bcast()`

596:   If `count` is not provided and the number of items read is less than
597:   the maximum number of items to read, then this routine errors.

599:   `PetscBinarySynchronizedRead()` uses byte swapping to work on all machines.
600:   The files  are written using big-endian ordering to the file. On little-endian machines the numbers
601:   are converted to the big-endian format when they are written to disk.
602:   When PETSc is configured using `./configure with --with-64-bit-indices` the integers are written to the
603:   file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices`
604:   is used.

606: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedWrite()`,
607:           `PetscBinarySynchronizedSeek()`
608: @*/
609: PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm, int fd, void *data, PetscInt num, PetscInt *count, PetscDataType type)
610: {
611:   PetscMPIInt  rank, size;
612:   MPI_Datatype mtype;
613:   PetscInt     ibuf[2] = {0, 0};
614:   char        *fname   = NULL;
615:   void        *fptr    = NULL;

617:   PetscFunctionBegin;
618:   if (type == PETSC_FUNCTION) {
619:     num   = 64;
620:     type  = PETSC_CHAR;
621:     fname = (char *)malloc(num * sizeof(char));
622:     fptr  = data;
623:     data  = (void *)fname;
624:     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
625:   }

627:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
628:   PetscCallMPI(MPI_Comm_size(comm, &size));
629:   if (rank == 0) ibuf[0] = PetscBinaryRead(fd, data, num, count ? &ibuf[1] : NULL, type);
630:   PetscCallMPI(MPI_Bcast(ibuf, 2, MPIU_INT, 0, comm));
631:   PetscCall((PetscErrorCode)ibuf[0]);

633:   /* skip MPI call on potentially huge amounts of data when running with one process; this allows the amount of data to basically unlimited in that case */
634:   if (size > 1) {
635:     PetscCall(PetscDataTypeToMPIDataType(type, &mtype));
636:     PetscCallMPI(MPI_Bcast(data, count ? ibuf[1] : num, mtype, 0, comm));
637:   }
638:   if (count) *count = ibuf[1];

640:   if (type == PETSC_FUNCTION) {
641: #if defined(PETSC_SERIALIZE_FUNCTIONS)
642:     PetscCall(PetscDLLibrarySym(PETSC_COMM_SELF, &PetscDLLibrariesLoaded, NULL, fname, (void **)fptr));
643: #else
644:     *(void **)fptr = NULL;
645: #endif
646:     free(fname);
647:   }
648:   PetscFunctionReturn(PETSC_SUCCESS);
649: }

651: /*@C
652:   PetscBinarySynchronizedWrite - writes to a binary file.

654:   Collective

656:   Input Parameters:
657: + comm - the MPI communicator
658: . fd   - the file
659: . n    - the number of items to write
660: . p    - the buffer, an array of the type that matches the value in `type`
661: - type - the type of items to write (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

663:   Level: developer

665:   Notes:
666:   MPI rank 0 does a `PetscBinaryWrite()` the values on other MPI processes are not used

668:   The files  are written using big-endian ordering to the file. On little-endian machines the numbers
669:   are converted to the big-endian format when they are written to disk.
670:   When PETSc is configured using `./configure with --with-64-bit-indices` the integers are written to the
671:   file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices`
672:   is used.

674:   Because byte-swapping may be done on the values in data it cannot be declared const

676:   This is NOT like `PetscSynchronizedFPrintf()`! This routine ignores calls on all but MPI rank 0,
677:   while `PetscSynchronizedFPrintf()` has all MPI processes print their strings in order.

679: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedRead()`,
680:           `PetscBinarySynchronizedSeek()`
681: @*/
682: PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm, int fd, const void *p, PetscInt n, PetscDataType type)
683: {
684:   PetscMPIInt rank;

686:   PetscFunctionBegin;
687:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
688:   if (rank == 0) PetscCall(PetscBinaryWrite(fd, p, n, type));
689:   PetscFunctionReturn(PETSC_SUCCESS);
690: }

692: /*@C
693:   PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.

695:   Input Parameters:
696: + comm   - the communicator to read with
697: . fd     - the file
698: . whence - see `PetscBinarySeekType` for possible values
699: - off    - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
700:             etc. in your calculation rather than `sizeof()` to compute byte lengths.

702:   Output Parameter:
703: . offset - new offset in file

705:   Level: developer

707: .seealso: `PetscBinaryRead()`, `PetscBinarySeekType`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,

709: @*/
710: PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm, int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
711: {
712:   PetscMPIInt rank;

714:   PetscFunctionBegin;
715:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
716:   if (rank == 0) PetscCall(PetscBinarySeek(fd, off, whence, offset));
717:   PetscFunctionReturn(PETSC_SUCCESS);
718: }

720: #if defined(PETSC_HAVE_MPIIO)

722:   #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
723: /*
724:       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
725:     These are set into MPI in PetscInitialize() via MPI_Register_datarep()

727:     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)

729:     The next three routines are not used because MPICH does not support their use

731: */
732: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype, MPI_Aint *file_extent, void *extra_state)
733: {
734:   MPI_Aint    ub;
735:   PetscMPIInt ierr;

737:   ierr = MPI_Type_get_extent(datatype, &ub, file_extent);
738:   return ierr;
739: }

741: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
742: {
743:   PetscDataType pdtype;
744:   PetscMPIInt   ierr;
745:   size_t        dsize;

747:   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
748:   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));

750:   /* offset is given in units of MPI_Datatype */
751:   userbuf = ((char *)userbuf) + dsize * position;

753:   PetscCall(PetscMemcpy(userbuf, filebuf, count * dsize));
754:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(userbuf, pdtype, count));
755:   return ierr;
756: }

758: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
759: {
760:   PetscDataType pdtype;
761:   PetscMPIInt   ierr;
762:   size_t        dsize;

764:   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
765:   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));

767:   /* offset is given in units of MPI_Datatype */
768:   userbuf = ((char *)userbuf) + dsize * position;

770:   PetscCall(PetscMemcpy(filebuf, userbuf, count * dsize));
771:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(filebuf, pdtype, count));
772:   return ierr;
773: }
774:   #endif

776: PetscErrorCode MPIU_File_write_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
777: {
778:   PetscDataType pdtype;

780:   PetscFunctionBegin;
781:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
782:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
783:   PetscCallMPI(MPI_File_write_all(fd, data, cnt, dtype, status));
784:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
785:   PetscFunctionReturn(PETSC_SUCCESS);
786: }

788: PetscErrorCode MPIU_File_read_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
789: {
790:   PetscDataType pdtype;

792:   PetscFunctionBegin;
793:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
794:   PetscCallMPI(MPI_File_read_all(fd, data, cnt, dtype, status));
795:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
796:   PetscFunctionReturn(PETSC_SUCCESS);
797: }

799: PetscErrorCode MPIU_File_write_at(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
800: {
801:   PetscDataType pdtype;

803:   PetscFunctionBegin;
804:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
805:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
806:   PetscCallMPI(MPI_File_write_at(fd, off, data, cnt, dtype, status));
807:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
808:   PetscFunctionReturn(PETSC_SUCCESS);
809: }

811: PetscErrorCode MPIU_File_read_at(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
812: {
813:   PetscDataType pdtype;

815:   PetscFunctionBegin;
816:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
817:   PetscCallMPI(MPI_File_read_at(fd, off, data, cnt, dtype, status));
818:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
819:   PetscFunctionReturn(PETSC_SUCCESS);
820: }

822: PetscErrorCode MPIU_File_write_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
823: {
824:   PetscDataType pdtype;

826:   PetscFunctionBegin;
827:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
828:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
829:   PetscCallMPI(MPI_File_write_at_all(fd, off, data, cnt, dtype, status));
830:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
831:   PetscFunctionReturn(PETSC_SUCCESS);
832: }

834: PetscErrorCode MPIU_File_read_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
835: {
836:   PetscDataType pdtype;

838:   PetscFunctionBegin;
839:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
840:   PetscCallMPI(MPI_File_read_at_all(fd, off, data, cnt, dtype, status));
841:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
842:   PetscFunctionReturn(PETSC_SUCCESS);
843: }

845: #endif