Actual source code: sysio.c

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

248: /*@C
249:   PetscBinaryRead - Reads from a binary file.

251:   Not Collective

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

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

262:   Level: developer

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

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

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

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

292:   PetscFunctionBegin;
293:   if (count) *count = 0;
294:   PetscCheck(num >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to read a negative amount of data %" PetscCount_FMT, num);
295:   if (!num) PetscFunctionReturn(PETSC_SUCCESS);

297:   if (type == PETSC_FUNCTION) {
298:     m     = 64;
299:     type  = PETSC_CHAR;
300:     fname = (char *)malloc(m * sizeof(char));
301:     p     = fname;
302:     ptmp  = (void *)fname;
303:     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
304:   }
305:   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(num);

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

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

320:   m *= typesize;

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

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

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

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

350:   if (type == PETSC_FUNCTION) {
351: #if defined(PETSC_SERIALIZE_FUNCTIONS)
352:     PetscCall(PetscDLSym(NULL, fname, (void **)data));
353: #else
354:     *(void **)data = NULL;
355: #endif
356:     free(fname);
357:   }
358:   PetscFunctionReturn(PETSC_SUCCESS);
359: }

361: /*@C
362:   PetscBinaryWrite - Writes to a binary file.

364:   Not Collective

366:   Input Parameters:
367: + fd   - the file
368: . p    - the buffer, an array of the type that matches the value in `type`
369: . n    - the number of items to write
370: - type - the type of items to read (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

372:   Level: advanced

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

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

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

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

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

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

397: .seealso: `PetscBinaryRead()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
398:           `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
399: @*/
400: PetscErrorCode PetscBinaryWrite(int fd, const void *p, PetscCount n, PetscDataType type)
401: {
402:   const char  *pp = (char *)p;
403:   size_t       err, m = (size_t)n, wsize;
404:   const size_t maxblock = 65536;
405:   const void  *ptmp     = p;
406:   char        *fname    = NULL;
407: #if defined(PETSC_USE_REAL___FLOAT128)
408:   PetscBool  writedouble = PETSC_FALSE;
409:   double    *ppp;
410:   PetscReal *pv;
411: #endif
412:   PetscDataType wtype = type;

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

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

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

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

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

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

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

481:   if (type == PETSC_FUNCTION) free(fname);
482: #if defined(PETSC_USE_REAL___FLOAT128)
483:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) PetscCall(PetscFree(ppp));
484: #endif
485:   PetscFunctionReturn(PETSC_SUCCESS);
486: }

488: /*@
489:   PetscBinaryOpen - Opens a PETSc binary file.

491:   Not Collective

493:   Input Parameters:
494: + name - filename
495: - mode - open mode of binary file, one of `FILE_MODE_READ`, `FILE_MODE_WRITE`, `FILE_MODE_APPEND`

497:   Output Parameter:
498: . fd - the file

500:   Level: advanced

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

525: /*@
526:   PetscBinaryClose - Closes a PETSc binary file.

528:   Not Collective

530:   Output Parameter:
531: . fd - the file

533:   Level: advanced

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

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

548:   Not Collective, No Fortran Support

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

556:   Output Parameter:
557: . offset - new offset in file

559:   Level: developer

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

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

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

586:   Collective, No Fortran Support

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

594:   Output Parameters:
595: + data  - the buffer, an array of the type that matches the value in `type`
596: - count - the number of items read, optional

598:   Level: developer

600:   Notes:
601:   Does a `PetscBinaryRead()` followed by an `MPI_Bcast()`

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

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

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

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

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

640:   /* 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 */
641:   if (size > 1) {
642:     PetscMPIInt cnt;

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

650:   if (type == PETSC_FUNCTION) {
651: #if defined(PETSC_SERIALIZE_FUNCTIONS)
652:     PetscCall(PetscDLLibrarySym(PETSC_COMM_SELF, &PetscDLLibrariesLoaded, NULL, fname, (void **)fptr));
653: #else
654:     *(void **)fptr = NULL;
655: #endif
656:     free(fname);
657:   }
658:   PetscFunctionReturn(PETSC_SUCCESS);
659: }

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

664:   Collective, No Fortran Support

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

673:   Level: developer

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

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

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

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

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

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

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

705:   No Fortran Support

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

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

717:   Level: developer

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

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

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

732: #if defined(PETSC_HAVE_MPIIO)

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

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

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

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

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

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

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

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

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

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

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

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

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

788: PetscErrorCode MPIU_File_write_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:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
795:   PetscCallMPI(MPI_File_write_all(fd, data, cnt, dtype, status));
796:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
797:   PetscFunctionReturn(PETSC_SUCCESS);
798: }

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

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

811: PetscErrorCode MPIU_File_write_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:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
818:   PetscCallMPI(MPI_File_write_at(fd, off, data, cnt, dtype, status));
819:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
820:   PetscFunctionReturn(PETSC_SUCCESS);
821: }

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

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

834: PetscErrorCode MPIU_File_write_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:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
841:   PetscCallMPI(MPI_File_write_at_all(fd, off, data, cnt, dtype, status));
842:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
843:   PetscFunctionReturn(PETSC_SUCCESS);
844: }

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

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

857: #endif