Actual source code: sysio.c

  1: #include <petscsys.h>
  2: #include <errno.h>
  3: #include <fcntl.h>
  4: #if PetscDefined(HAVE_UNISTD_H)
  5:   #include <unistd.h>
  6: #endif
  7: #if PetscDefined(HAVE_IO_H)
  8:   #include <io.h>
  9: #endif
 10: #if !PetscDefined(HAVE_O_BINARY)
 11:   #define O_BINARY 0
 12: #endif

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

 16: /*
 17:   PetscByteSwapEnum - Swap bytes in a  PETSc Enum

 19: */
 20: static PetscErrorCode PetscByteSwapEnum(PetscEnum *buff, PetscCount n)
 21: {
 22:   PetscCount i, j;
 23:   PetscEnum  tmp = ENUM_DUMMY;
 24:   char      *ptr1, *ptr2 = (char *)&tmp;

 26:   PetscFunctionBegin;
 27:   for (j = 0; j < n; j++) {
 28:     ptr1 = (char *)(buff + j);
 29:     for (i = 0; i < (PetscCount)sizeof(PetscEnum); i++) ptr2[i] = ptr1[sizeof(PetscEnum) - 1 - i];
 30:     for (i = 0; i < (PetscCount)sizeof(PetscEnum); i++) ptr1[i] = ptr2[i];
 31:   }
 32:   PetscFunctionReturn(PETSC_SUCCESS);
 33: }

 35: /*
 36:   PetscByteSwapBool - Swap bytes in a  PETSc Bool

 38: */
 39: static PetscErrorCode PetscByteSwapBool(PetscBool *buff, PetscCount n)
 40: {
 41:   PetscCount i, j;
 42:   PetscBool  tmp = PETSC_FALSE;
 43:   char      *ptr1, *ptr2 = (char *)&tmp;

 45:   PetscFunctionBegin;
 46:   for (j = 0; j < n; j++) {
 47:     ptr1 = (char *)(buff + j);
 48:     for (i = 0; i < (PetscCount)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool) - 1 - i];
 49:     for (i = 0; i < (PetscCount)sizeof(PetscBool); i++) ptr1[i] = ptr2[i];
 50:   }
 51:   PetscFunctionReturn(PETSC_SUCCESS);
 52: }

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

 57: */
 58: static PetscErrorCode PetscByteSwapInt(PetscInt *buff, PetscCount n)
 59: {
 60:   PetscCount i, j;
 61:   PetscInt   tmp = 0;
 62:   char      *ptr1, *ptr2 = (char *)&tmp;

 64:   PetscFunctionBegin;
 65:   for (j = 0; j < n; j++) {
 66:     ptr1 = (char *)(buff + j);
 67:     for (i = 0; i < (PetscCount)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt) - 1 - i];
 68:     for (i = 0; i < (PetscCount)sizeof(PetscInt); i++) ptr1[i] = ptr2[i];
 69:   }
 70:   PetscFunctionReturn(PETSC_SUCCESS);
 71: }

 73: /*
 74:   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64-bits)

 76: */
 77: static PetscErrorCode PetscByteSwapInt64(PetscInt64 *buff, PetscCount n)
 78: {
 79:   PetscCount i, j;
 80:   PetscInt64 tmp = 0;
 81:   char      *ptr1, *ptr2 = (char *)&tmp;

 83:   PetscFunctionBegin;
 84:   for (j = 0; j < n; j++) {
 85:     ptr1 = (char *)(buff + j);
 86:     for (i = 0; i < (PetscCount)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64) - 1 - i];
 87:     for (i = 0; i < (PetscCount)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i];
 88:   }
 89:   PetscFunctionReturn(PETSC_SUCCESS);
 90: }

 92: /*
 93:   PetscByteSwapInt32 - Swap bytes in a  PETSc integer (32-bits)

 95: */
 96: static PetscErrorCode PetscByteSwapInt32(PetscInt32 *buff, PetscCount n)
 97: {
 98:   PetscCount i, j;
 99:   PetscInt32 tmp = 0;
100:   char      *ptr1, *ptr2 = (char *)&tmp;

102:   PetscFunctionBegin;
103:   for (j = 0; j < n; j++) {
104:     ptr1 = (char *)(buff + j);
105:     for (i = 0; i < (PetscCount)sizeof(PetscInt32); i++) ptr2[i] = ptr1[sizeof(PetscInt32) - 1 - i];
106:     for (i = 0; i < (PetscCount)sizeof(PetscInt32); i++) ptr1[i] = ptr2[i];
107:   }
108:   PetscFunctionReturn(PETSC_SUCCESS);
109: }

111: /*
112:   PetscByteSwapShort - Swap bytes in a short
113: */
114: static PetscErrorCode PetscByteSwapShort(short *buff, PetscCount n)
115: {
116:   PetscCount i, j;
117:   short      tmp;
118:   char      *ptr1, *ptr2 = (char *)&tmp;

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

137:   PetscFunctionBegin;
138:   for (j = 0; j < n; j++) {
139:     ptr1 = (char *)(buff + j);
140:     for (i = 0; i < (PetscCount)sizeof(long); i++) ptr2[i] = ptr1[sizeof(long) - 1 - i];
141:     for (i = 0; i < (PetscCount)sizeof(long); i++) ptr1[i] = ptr2[i];
142:   }
143:   PetscFunctionReturn(PETSC_SUCCESS);
144: }

146: /*
147:   PetscByteSwapReal - Swap bytes in a PetscReal
148: */
149: static PetscErrorCode PetscByteSwapReal(PetscReal *buff, PetscCount n)
150: {
151:   PetscCount i, j;
152:   PetscReal  tmp, *buff1 = buff;
153:   char      *ptr1, *ptr2 = (char *)&tmp;

155:   PetscFunctionBegin;
156:   for (j = 0; j < n; j++) {
157:     ptr1 = (char *)(buff1 + j);
158:     for (i = 0; i < (PetscCount)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i];
159:     for (i = 0; i < (PetscCount)sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
160:   }
161:   PetscFunctionReturn(PETSC_SUCCESS);
162: }

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

178:   PetscFunctionBegin;
179: #if PetscDefined(USE_COMPLEX)
180:   n *= 2;
181: #endif
182:   for (j = 0; j < n; j++) {
183:     ptr1 = (char *)(buff1 + j);
184:     for (i = 0; i < (PetscCount)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i];
185:     for (i = 0; i < (PetscCount)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, PetscCount n)
194: {
195:   PetscCount i, j;
196:   double     tmp, *buff1 = 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 < (PetscCount)sizeof(double); i++) ptr2[i] = ptr1[sizeof(double) - 1 - i];
203:     for (i = 0; i < (PetscCount)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, PetscCount n)
212: {
213:   PetscCount i, j;
214:   float      tmp, *buff1 = 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 < (PetscCount)sizeof(float); i++) ptr2[i] = ptr1[sizeof(float) - 1 - i];
221:     for (i = 0; i < (PetscCount)sizeof(float); i++) ptr1[i] = ptr2[i];
222:   }
223:   PetscFunctionReturn(PETSC_SUCCESS);
224: }

226: /*@
227:   PetscByteSwap - Reverse the byte order of an array of values of a given `PetscDataType`, in place

229:   Not Collective; No Fortran Support

231:   Input Parameters:
232: + data   - the array of values to byte-swap in place
233: . pdtype - the `PetscDataType` of the values (e.g. `PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`)
234: - count  - number of values in `data`

236:   Level: developer

238:   Note:
239:   Used by binary I/O routines to convert between little-endian and big-endian representations.

241: .seealso: `PetscDataType`, `PetscViewerBinaryRead()`, `PetscViewerBinaryWrite()`
242: @*/
243: PetscErrorCode PetscByteSwap(void *data, PetscDataType pdtype, PetscCount count)
244: {
245:   PetscFunctionBegin;
246:   if (pdtype == PETSC_INT) PetscCall(PetscByteSwapInt((PetscInt *)data, count));
247:   else if (pdtype == PETSC_ENUM) PetscCall(PetscByteSwapEnum((PetscEnum *)data, count));
248:   else if (pdtype == PETSC_BOOL) PetscCall(PetscByteSwapBool((PetscBool *)data, count));
249:   else if (pdtype == PETSC_SCALAR) PetscCall(PetscByteSwapScalar((PetscScalar *)data, count));
250:   else if (pdtype == PETSC_REAL) PetscCall(PetscByteSwapReal((PetscReal *)data, count));
251:   else if (pdtype == PETSC_COMPLEX) PetscCall(PetscByteSwapReal((PetscReal *)data, 2 * count));
252:   else if (pdtype == PETSC_INT64) PetscCall(PetscByteSwapInt64((PetscInt64 *)data, count));
253:   else if (pdtype == PETSC_COUNT) PetscCall(PetscByteSwapInt64((PetscInt64 *)data, count));
254:   else if (pdtype == PETSC_INT32) PetscCall(PetscByteSwapInt32((PetscInt32 *)data, count));
255:   else if (pdtype == PETSC_DOUBLE) PetscCall(PetscByteSwapDouble((double *)data, count));
256:   else if (pdtype == PETSC_FLOAT) PetscCall(PetscByteSwapFloat((float *)data, count));
257:   else if (pdtype == PETSC_SHORT) PetscCall(PetscByteSwapShort((short *)data, count));
258:   else if (pdtype == PETSC_LONG) PetscCall(PetscByteSwapLong((long *)data, count));
259:   else if (pdtype == PETSC_CHAR) PetscFunctionReturn(PETSC_SUCCESS);
260:   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown type: %d", pdtype);
261:   PetscFunctionReturn(PETSC_SUCCESS);
262: }

264: /*@
265:   PetscBinaryRead - Reads from a binary file.

267:   Not Collective

269:   Input Parameters:
270: + fd   - the file descriptor
271: . num  - the maximum number of items to read
272: - type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)

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

278:   Level: developer

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

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

291:   Fortran Note:
292:   There are different functions for each datatype, for example `PetscBinaryReadInt()`

294: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
295:           `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
296: @*/
297: PetscErrorCode PetscBinaryRead(int fd, void *data, PetscCount num, PetscInt *count, PetscDataType type)
298: {
299:   size_t typesize, m = (size_t)num, n = 0, maxblock = 65536;
300:   char  *p = (char *)data;
301: #if PetscDefined(USE_REAL___FLOAT128)
302:   PetscBool readdouble = PETSC_FALSE;
303:   double   *pdouble;
304: #endif
305:   void *ptmp  = data;
306:   char *fname = NULL;

308:   PetscFunctionBegin;
309:   if (count) *count = 0;
310:   PetscCheck(num >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to read a negative amount of data %" PetscCount_FMT, num);
311:   if (!num) PetscFunctionReturn(PETSC_SUCCESS);

313:   if (type == PETSC_FUNCTION) {
314:     m     = 64;
315:     type  = PETSC_CHAR;
316:     fname = (char *)malloc(m * sizeof(char));
317:     p     = fname;
318:     ptmp  = (void *)fname;
319:     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
320:   }
321:   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(num);

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

325: #if PetscDefined(USE_REAL___FLOAT128)
326:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-binary_read_double", &readdouble, NULL));
327:   /* If using __float128 precision we still read in doubles from file */
328:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
329:     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
330:     PetscCall(PetscMalloc1(cnt, &pdouble));
331:     p = (char *)pdouble;
332:     typesize /= 2;
333:   }
334: #endif

336:   m *= typesize;

338:   while (m) {
339:     size_t len = (m < maxblock) ? m : maxblock;
340:     int    ret = (int)read(fd, p, len);
341:     if (ret < 0 && errno == EINTR) continue;
342:     if (!ret && len > 0) break; /* Proxy for EOF */
343:     PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file due to \"%s\"", strerror(errno));
344:     m -= (size_t)ret;
345:     p += ret;
346:     n += (size_t)ret;
347:   }
348:   PetscCheck(!m || count, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Read past end of file");

350:   num = n / typesize;                             /* Should we require `n % typesize == 0` ? */
351:   if (count) PetscCall(PetscIntCast(num, count)); /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */

353: #if PetscDefined(USE_REAL___FLOAT128)
354:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
355:     PetscInt   i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
356:     PetscReal *preal = (PetscReal *)data;
357:     if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwapDouble(pdouble, cnt));
358:     for (i = 0; i < cnt; i++) preal[i] = pdouble[i];
359:     PetscCall(PetscFree(pdouble));
360:     PetscFunctionReturn(PETSC_SUCCESS);
361:   }
362: #endif

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

366:   if (type == PETSC_FUNCTION) {
367:     *(void **)data = NULL;
368:     free(fname);
369:   }
370:   PetscFunctionReturn(PETSC_SUCCESS);
371: }

373: /*@
374:   PetscBinaryWrite - Writes to a binary file.

376:   Not Collective

378:   Input Parameters:
379: + fd   - the file
380: . p    - the buffer, an array of the type that matches the value in `type`
381: . n    - the number of items to write
382: - type - the type of items to read (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

384:   Level: advanced

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

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

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

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

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

406:   Fortran Note:
407:   There are different functions for each datatype, for example `PetscBinaryWriteInt()`

409: .seealso: `PetscBinaryRead()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
410:           `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
411: @*/
412: PetscErrorCode PetscBinaryWrite(int fd, const void *p, PetscCount n, PetscDataType type)
413: {
414:   const char  *pp = (char *)p;
415:   size_t       err, m = (size_t)n, wsize;
416:   const size_t maxblock = 65536;
417:   const void  *ptmp     = p;
418:   char        *fname    = NULL;
419: #if PetscDefined(USE_REAL___FLOAT128)
420:   PetscBool  writedouble = PETSC_FALSE;
421:   double    *ppp;
422:   PetscReal *pv;
423: #endif
424:   PetscDataType wtype = type;

426:   PetscFunctionBegin;
427:   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to write a negative amount of data %" PetscCount_FMT, n);
428:   if (!n) PetscFunctionReturn(PETSC_SUCCESS);

430:   if (type == PETSC_FUNCTION) {
431:     m     = 64;
432:     fname = (char *)malloc(m * sizeof(char));
433:     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
434:     PetscCall(PetscStrncpy(fname, "", m));
435:     wtype = PETSC_CHAR;
436:     pp    = fname;
437:     ptmp  = (void *)fname;
438:   }

440: #if PetscDefined(USE_REAL___FLOAT128)
441:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-binary_write_double", &writedouble, NULL));
442:   /* If using __float128 precision we still write in doubles to file */
443:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
444:     wtype = PETSC_DOUBLE;
445:     PetscCall(PetscMalloc1(n, &ppp));
446:     pv = (PetscReal *)pp;
447:     for (PetscCount i = 0; i < n; i++) ppp[i] = (double)pv[i];
448:     pp   = (char *)ppp;
449:     ptmp = (char *)ppp;
450:   }
451: #endif

453:   if (wtype == PETSC_INT) m *= sizeof(PetscInt);
454:   else if (wtype == PETSC_SCALAR) m *= sizeof(PetscScalar);
455: #if PetscDefined(HAVE_COMPLEX)
456:   else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
457: #endif
458:   else if (wtype == PETSC_REAL) m *= sizeof(PetscReal);
459:   else if (wtype == PETSC_DOUBLE) m *= sizeof(double);
460:   else if (wtype == PETSC_FLOAT) m *= sizeof(float);
461:   else if (wtype == PETSC_SHORT) m *= sizeof(short);
462:   else if (wtype == PETSC_LONG) m *= sizeof(long);
463:   else if (wtype == PETSC_CHAR) m *= sizeof(char);
464:   else if (wtype == PETSC_ENUM) m *= sizeof(PetscEnum);
465:   else if (wtype == PETSC_BOOL) m *= sizeof(PetscBool);
466:   else if (wtype == PETSC_INT64) m *= sizeof(PetscInt64);
467:   else if (wtype == PETSC_INT32) m *= sizeof(PetscInt32);
468:   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m) * sizeof(char);
469:   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown type: %d", wtype);

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

473:   while (m) {
474:     wsize = (m < maxblock) ? m : maxblock;
475:     err   = (size_t)write(fd, pp, wsize);
476:     if (errno == EINTR) continue;
477:     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));
478:     m -= wsize;
479:     pp += wsize;
480:   }

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

484:   if (type == PETSC_FUNCTION) free(fname);
485: #if PetscDefined(USE_REAL___FLOAT128)
486:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) PetscCall(PetscFree(ppp));
487: #endif
488:   PetscFunctionReturn(PETSC_SUCCESS);
489: }

491: /*@
492:   PetscBinaryOpen - Opens a PETSc binary file.

494:   Not Collective

496:   Input Parameters:
497: + name - filename
498: - mode - open mode of binary file, one of `FILE_MODE_READ`, `FILE_MODE_WRITE`, `FILE_MODE_APPEND`

500:   Output Parameter:
501: . fd - the file

503:   Level: advanced

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

528: /*@
529:   PetscBinaryClose - Closes a PETSc binary file.

531:   Not Collective

533:   Output Parameter:
534: . fd - the file

536:   Level: advanced

538: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
539:           `PetscBinarySynchronizedSeek()`
540: @*/
541: PetscErrorCode PetscBinaryClose(int fd)
542: {
543:   PetscFunctionBegin;
544:   PetscCheck(!close(fd), PETSC_COMM_SELF, PETSC_ERR_SYS, "close() failed on file descriptor");
545:   PetscFunctionReturn(PETSC_SUCCESS);
546: }

548: /*@
549:   PetscBinarySeek - Moves the file pointer on a PETSc binary file.

551:   Not Collective, No Fortran Support

553:   Input Parameters:
554: + fd     - the file
555: . off    - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
556:            etc. in your calculation rather than `sizeof()` to compute byte lengths.
557: - whence - see `PetscBinarySeekType` for possible values

559:   Output Parameter:
560: . offset - new offset in file

562:   Level: developer

564: .seealso: `PetscBinaryRead()`, `PetscBinarySeekType`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
565:           `PetscBinarySynchronizedSeek()`
566: @*/
567: PetscErrorCode PetscBinarySeek(int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
568: {
569:   int iwhence = 0;

571:   PetscFunctionBegin;
572:   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
573:   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
574:   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
575:   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown seek location");
576: #if PetscDefined(HAVE_LSEEK)
577:   *offset = lseek(fd, off, iwhence);
578: #elif PetscDefined(HAVE__LSEEK)
579:   *offset = _lseek(fd, (long)off, iwhence);
580: #else
581:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "System does not have a way of seeking on a file");
582: #endif
583:   PetscFunctionReturn(PETSC_SUCCESS);
584: }

586: /*@
587:   PetscBinarySynchronizedRead - Reads from a binary file, all MPI processes get the same values

589:   Collective, No Fortran Support

591:   Input Parameters:
592: + comm - the MPI communicator
593: . fd   - the file descriptor
594: . num  - the maximum number of items to read
595: - type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)

597:   Output Parameters:
598: + data  - the buffer, an array of the type that matches the value in `type`
599: - count - the number of items read, optional

601:   Level: developer

603:   Notes:
604:   Does a `PetscBinaryRead()` followed by an `MPI_Bcast()`

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

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

616: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedWrite()`,
617:           `PetscBinarySynchronizedSeek()`
618: @*/
619: PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm, int fd, void *data, PetscInt num, PetscInt *count, PetscDataType type)
620: {
621:   PetscMPIInt  rank, size;
622:   MPI_Datatype mtype;
623:   PetscInt     ibuf[2] = {0, 0};
624:   char        *fname   = NULL;
625:   void        *fptr    = NULL;

627:   PetscFunctionBegin;
628:   if (type == PETSC_FUNCTION) {
629:     num   = 64;
630:     type  = PETSC_CHAR;
631:     fname = (char *)malloc(num * sizeof(char));
632:     fptr  = data;
633:     data  = (void *)fname;
634:     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
635:   }

637:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
638:   PetscCallMPI(MPI_Comm_size(comm, &size));
639:   if (rank == 0) ibuf[0] = (PetscInt)PetscBinaryRead(fd, data, num, count ? &ibuf[1] : NULL, type);
640:   PetscCallMPI(MPI_Bcast(ibuf, 2, MPIU_INT, 0, comm));
641:   PetscCall((PetscErrorCode)ibuf[0]);

643:   /* 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 */
644:   if (size > 1) {
645:     PetscMPIInt cnt;

647:     PetscCall(PetscMPIIntCast(count ? ibuf[1] : num, &cnt));
648:     PetscCall(PetscDataTypeToMPIDataType(type, &mtype));
649:     PetscCallMPI(MPI_Bcast(data, cnt, mtype, 0, comm));
650:   }
651:   if (count) *count = ibuf[1];

653:   if (type == PETSC_FUNCTION) {
654:     *(void **)fptr = NULL;
655:     free(fname);
656:   }
657:   PetscFunctionReturn(PETSC_SUCCESS);
658: }

660: /*@
661:   PetscBinarySynchronizedWrite - writes to a binary file.

663:   Collective, No Fortran Support

665:   Input Parameters:
666: + comm - the MPI communicator
667: . fd   - the file
668: . n    - the number of items to write
669: . p    - the buffer, an array of the type that matches the value in `type`
670: - type - the type of items to write (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

672:   Level: developer

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

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

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

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

688: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedRead()`,
689:           `PetscBinarySynchronizedSeek()`
690: @*/
691: PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm, int fd, const void *p, PetscInt n, PetscDataType type)
692: {
693:   PetscMPIInt rank;

695:   PetscFunctionBegin;
696:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
697:   if (rank == 0) PetscCall(PetscBinaryWrite(fd, p, n, type));
698:   PetscFunctionReturn(PETSC_SUCCESS);
699: }

701: /*@
702:   PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.

704:   No Fortran Support

706:   Input Parameters:
707: + comm   - the communicator to read with
708: . fd     - the file
709: . whence - see `PetscBinarySeekType` for possible values
710: - off    - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
711:             etc. in your calculation rather than `sizeof()` to compute byte lengths.

713:   Output Parameter:
714: . offset - new offset in file

716:   Level: developer

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

720: @*/
721: PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm, int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
722: {
723:   PetscMPIInt rank;

725:   PetscFunctionBegin;
726:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
727:   if (rank == 0) PetscCall(PetscBinarySeek(fd, off, whence, offset));
728:   PetscFunctionReturn(PETSC_SUCCESS);
729: }

731: #if PetscDefined(HAVE_MPIIO)

733:   #if PetscDefined(USE_PETSC_MPI_EXTERNAL32)
734: /*
735:       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
736:     These are set into MPI in PetscInitialize() via MPI_Register_datarep()

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

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

742: */
743: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype, MPI_Aint *file_extent, void *extra_state)
744: {
745:   MPI_Aint    ub;
746:   PetscMPIInt ierr;

748:   ierr = MPI_Type_get_extent(datatype, &ub, file_extent);
749:   return ierr;
750: }

752: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
753: {
754:   PetscDataType pdtype;
755:   PetscMPIInt   ierr;
756:   size_t        dsize;

758:   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
759:   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));

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

764:   PetscCall(PetscMemcpy(userbuf, filebuf, count * dsize));
765:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(userbuf, pdtype, count));
766:   return ierr;
767: }

769: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
770: {
771:   PetscDataType pdtype;
772:   PetscMPIInt   ierr;
773:   size_t        dsize;

775:   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
776:   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));

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

781:   PetscCall(PetscMemcpy(filebuf, userbuf, count * dsize));
782:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(filebuf, pdtype, count));
783:   return ierr;
784: }
785:   #endif

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

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

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

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

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

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

822: PetscErrorCode MPIU_File_read_at(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:   PetscCallMPI(MPI_File_read_at(fd, off, data, cnt, dtype, status));
829:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
830:   PetscFunctionReturn(PETSC_SUCCESS);
831: }

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

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

845: PetscErrorCode MPIU_File_read_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
846: {
847:   PetscDataType pdtype;

849:   PetscFunctionBegin;
850:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
851:   PetscCallMPI(MPI_File_read_at_all(fd, off, data, cnt, dtype, status));
852:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
853:   PetscFunctionReturn(PETSC_SUCCESS);
854: }

856: #endif