xref: /petsc/src/sys/fileio/sysio.c (revision 5520554388890bd89a1c1cf7870aedf4e71d512f)
1 
2 /*
3    This file contains simple binary read/write routines.
4  */
5 
6 #include <petscsys.h>
7 #include <petscbt.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #if defined(PETSC_HAVE_UNISTD_H)
11 #include <unistd.h>
12 #endif
13 #if defined(PETSC_HAVE_IO_H)
14 #include <io.h>
15 #endif
16 #if !defined(PETSC_HAVE_O_BINARY)
17 #define O_BINARY 0
18 #endif
19 
20 const char *const PetscFileModes[] = {"READ", "WRITE", "APPEND", "UPDATE", "APPEND_UPDATE", "PetscFileMode", "PETSC_FILE_", NULL};
21 
22 /* --------------------------------------------------------- */
23 /*
24   PetscByteSwapEnum - Swap bytes in a  PETSc Enum
25 
26 */
27 PetscErrorCode PetscByteSwapEnum(PetscEnum *buff, PetscInt n) {
28   PetscInt  i, j;
29   PetscEnum tmp = ENUM_DUMMY;
30   char     *ptr1, *ptr2 = (char *)&tmp;
31 
32   PetscFunctionBegin;
33   for (j = 0; j < n; j++) {
34     ptr1 = (char *)(buff + j);
35     for (i = 0; i < (PetscInt)sizeof(PetscEnum); i++) ptr2[i] = ptr1[sizeof(PetscEnum) - 1 - i];
36     for (i = 0; i < (PetscInt)sizeof(PetscEnum); i++) ptr1[i] = ptr2[i];
37   }
38   PetscFunctionReturn(0);
39 }
40 
41 /*
42   PetscByteSwapBool - Swap bytes in a  PETSc Bool
43 
44 */
45 PetscErrorCode PetscByteSwapBool(PetscBool *buff, PetscInt n) {
46   PetscInt  i, j;
47   PetscBool tmp = PETSC_FALSE;
48   char     *ptr1, *ptr2 = (char *)&tmp;
49 
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(0);
57 }
58 
59 /*
60   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64 bits)
61 
62 */
63 PetscErrorCode PetscByteSwapInt(PetscInt *buff, PetscInt n) {
64   PetscInt i, j, tmp = 0;
65   char    *ptr1, *ptr2 = (char *)&tmp;
66 
67   PetscFunctionBegin;
68   for (j = 0; j < n; j++) {
69     ptr1 = (char *)(buff + j);
70     for (i = 0; i < (PetscInt)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt) - 1 - i];
71     for (i = 0; i < (PetscInt)sizeof(PetscInt); i++) ptr1[i] = ptr2[i];
72   }
73   PetscFunctionReturn(0);
74 }
75 
76 /*
77   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64 bits)
78 
79 */
80 PetscErrorCode PetscByteSwapInt64(PetscInt64 *buff, PetscInt n) {
81   PetscInt   i, j;
82   PetscInt64 tmp = 0;
83   char      *ptr1, *ptr2 = (char *)&tmp;
84 
85   PetscFunctionBegin;
86   for (j = 0; j < n; j++) {
87     ptr1 = (char *)(buff + j);
88     for (i = 0; i < (PetscInt)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64) - 1 - i];
89     for (i = 0; i < (PetscInt)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i];
90   }
91   PetscFunctionReturn(0);
92 }
93 
94 /* --------------------------------------------------------- */
95 /*
96   PetscByteSwapShort - Swap bytes in a short
97 */
98 PetscErrorCode PetscByteSwapShort(short *buff, PetscInt n) {
99   PetscInt i, j;
100   short    tmp;
101   char    *ptr1, *ptr2 = (char *)&tmp;
102 
103   PetscFunctionBegin;
104   for (j = 0; j < n; j++) {
105     ptr1 = (char *)(buff + j);
106     for (i = 0; i < (PetscInt)sizeof(short); i++) ptr2[i] = ptr1[sizeof(short) - 1 - i];
107     for (i = 0; i < (PetscInt)sizeof(short); i++) ptr1[i] = ptr2[i];
108   }
109   PetscFunctionReturn(0);
110 }
111 /*
112   PetscByteSwapLong - Swap bytes in a long
113 */
114 PetscErrorCode PetscByteSwapLong(long *buff, PetscInt n) {
115   PetscInt i, j;
116   long     tmp;
117   char    *ptr1, *ptr2 = (char *)&tmp;
118 
119   PetscFunctionBegin;
120   for (j = 0; j < n; j++) {
121     ptr1 = (char *)(buff + j);
122     for (i = 0; i < (PetscInt)sizeof(long); i++) ptr2[i] = ptr1[sizeof(long) - 1 - i];
123     for (i = 0; i < (PetscInt)sizeof(long); i++) ptr1[i] = ptr2[i];
124   }
125   PetscFunctionReturn(0);
126 }
127 /* --------------------------------------------------------- */
128 /*
129   PetscByteSwapReal - Swap bytes in a PetscReal
130 */
131 PetscErrorCode PetscByteSwapReal(PetscReal *buff, PetscInt n) {
132   PetscInt  i, j;
133   PetscReal tmp, *buff1 = (PetscReal *)buff;
134   char     *ptr1, *ptr2 = (char *)&tmp;
135 
136   PetscFunctionBegin;
137   for (j = 0; j < n; j++) {
138     ptr1 = (char *)(buff1 + j);
139     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i];
140     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
141   }
142   PetscFunctionReturn(0);
143 }
144 /* --------------------------------------------------------- */
145 /*
146   PetscByteSwapScalar - Swap bytes in a PetscScalar
147   The complex case is dealt with with an array of PetscReal, twice as long.
148 */
149 PetscErrorCode PetscByteSwapScalar(PetscScalar *buff, PetscInt n) {
150   PetscInt  i, j;
151   PetscReal tmp, *buff1 = (PetscReal *)buff;
152   char     *ptr1, *ptr2 = (char *)&tmp;
153 
154   PetscFunctionBegin;
155 #if defined(PETSC_USE_COMPLEX)
156   n *= 2;
157 #endif
158   for (j = 0; j < n; j++) {
159     ptr1 = (char *)(buff1 + j);
160     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i];
161     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
162   }
163   PetscFunctionReturn(0);
164 }
165 /* --------------------------------------------------------- */
166 /*
167   PetscByteSwapDouble - Swap bytes in a double
168 */
169 PetscErrorCode PetscByteSwapDouble(double *buff, PetscInt n) {
170   PetscInt i, j;
171   double   tmp, *buff1 = (double *)buff;
172   char    *ptr1, *ptr2 = (char *)&tmp;
173 
174   PetscFunctionBegin;
175   for (j = 0; j < n; j++) {
176     ptr1 = (char *)(buff1 + j);
177     for (i = 0; i < (PetscInt)sizeof(double); i++) ptr2[i] = ptr1[sizeof(double) - 1 - i];
178     for (i = 0; i < (PetscInt)sizeof(double); i++) ptr1[i] = ptr2[i];
179   }
180   PetscFunctionReturn(0);
181 }
182 
183 /*
184   PetscByteSwapFloat - Swap bytes in a float
185 */
186 PetscErrorCode PetscByteSwapFloat(float *buff, PetscInt n) {
187   PetscInt i, j;
188   float    tmp, *buff1 = (float *)buff;
189   char    *ptr1, *ptr2 = (char *)&tmp;
190 
191   PetscFunctionBegin;
192   for (j = 0; j < n; j++) {
193     ptr1 = (char *)(buff1 + j);
194     for (i = 0; i < (PetscInt)sizeof(float); i++) ptr2[i] = ptr1[sizeof(float) - 1 - i];
195     for (i = 0; i < (PetscInt)sizeof(float); i++) ptr1[i] = ptr2[i];
196   }
197   PetscFunctionReturn(0);
198 }
199 
200 PetscErrorCode PetscByteSwap(void *data, PetscDataType pdtype, PetscInt count) {
201   PetscFunctionBegin;
202   if (pdtype == PETSC_INT) PetscCall(PetscByteSwapInt((PetscInt *)data, count));
203   else if (pdtype == PETSC_ENUM) PetscCall(PetscByteSwapEnum((PetscEnum *)data, count));
204   else if (pdtype == PETSC_BOOL) PetscCall(PetscByteSwapBool((PetscBool *)data, count));
205   else if (pdtype == PETSC_SCALAR) PetscCall(PetscByteSwapScalar((PetscScalar *)data, count));
206   else if (pdtype == PETSC_REAL) PetscCall(PetscByteSwapReal((PetscReal *)data, count));
207   else if (pdtype == PETSC_COMPLEX) PetscCall(PetscByteSwapReal((PetscReal *)data, 2 * count));
208   else if (pdtype == PETSC_INT64) PetscCall(PetscByteSwapInt64((PetscInt64 *)data, count));
209   else if (pdtype == PETSC_DOUBLE) PetscCall(PetscByteSwapDouble((double *)data, count));
210   else if (pdtype == PETSC_FLOAT) PetscCall(PetscByteSwapFloat((float *)data, count));
211   else if (pdtype == PETSC_SHORT) PetscCall(PetscByteSwapShort((short *)data, count));
212   else if (pdtype == PETSC_LONG) PetscCall(PetscByteSwapLong((long *)data, count));
213   PetscFunctionReturn(0);
214 }
215 
216 /*@C
217    PetscBinaryRead - Reads from a binary file.
218 
219    Not Collective
220 
221    Input Parameters:
222 +  fd - the file descriptor
223 .  num  - the maximum number of items to read
224 -  type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)
225 
226    Output Parameters:
227 +  data - the buffer
228 -  count - the number of items read, optional
229 
230    Level: developer
231 
232    Notes:
233    If count is not provided and the number of items read is less than
234    the maximum number of items to read, then this routine errors.
235 
236    `PetscBinaryRead()` uses byte swapping to work on all machines; the files
237    are written to file ALWAYS using big-endian ordering. On little-endian machines the numbers
238    are converted to the little-endian format when they are read in from the file.
239    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
240    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
241    is used.
242 
243 .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
244           `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
245 @*/
246 PetscErrorCode PetscBinaryRead(int fd, void *data, PetscInt num, PetscInt *count, PetscDataType type) {
247   size_t typesize, m = (size_t)num, n = 0, maxblock = 65536;
248   char  *p = (char *)data;
249 #if defined(PETSC_USE_REAL___FLOAT128)
250   PetscBool readdouble = PETSC_FALSE;
251   double   *pdouble;
252 #endif
253   void *ptmp  = data;
254   char *fname = NULL;
255 
256   PetscFunctionBegin;
257   if (count) *count = 0;
258   PetscCheck(num >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to read a negative amount of data %" PetscInt_FMT, num);
259   if (!num) PetscFunctionReturn(0);
260 
261   if (type == PETSC_FUNCTION) {
262     m     = 64;
263     type  = PETSC_CHAR;
264     fname = (char *)malloc(m * sizeof(char));
265     p     = (char *)fname;
266     ptmp  = (void *)fname;
267     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
268   }
269   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m);
270 
271   PetscCall(PetscDataTypeGetSize(type, &typesize));
272 
273 #if defined(PETSC_USE_REAL___FLOAT128)
274   PetscCall(PetscOptionsGetBool(NULL, NULL, "-binary_read_double", &readdouble, NULL));
275   /* If using __float128 precision we still read in doubles from file */
276   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
277     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
278     PetscCall(PetscMalloc1(cnt, &pdouble));
279     p = (char *)pdouble;
280     typesize /= 2;
281   }
282 #endif
283 
284   m *= typesize;
285 
286   while (m) {
287     size_t len = (m < maxblock) ? m : maxblock;
288     int    ret = (int)read(fd, p, len);
289     if (ret < 0 && errno == EINTR) continue;
290     if (!ret && len > 0) break; /* Proxy for EOF */
291     PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file, errno %d", errno);
292     m -= (size_t)ret;
293     p += ret;
294     n += (size_t)ret;
295   }
296   PetscCheck(!m || count, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Read past end of file");
297 
298   num = (PetscInt)(n / typesize); /* Should we require `n % typesize == 0` ? */
299   if (count) *count = num;        /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */
300 
301 #if defined(PETSC_USE_REAL___FLOAT128)
302   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
303     PetscInt   i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
304     PetscReal *preal = (PetscReal *)data;
305     if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwapDouble(pdouble, cnt));
306     for (i = 0; i < cnt; i++) preal[i] = pdouble[i];
307     PetscCall(PetscFree(pdouble));
308     PetscFunctionReturn(0);
309   }
310 #endif
311 
312   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(ptmp, type, num));
313 
314   if (type == PETSC_FUNCTION) {
315 #if defined(PETSC_SERIALIZE_FUNCTIONS)
316     PetscCall(PetscDLSym(NULL, fname, (void **)data));
317 #else
318     *(void **)data = NULL;
319 #endif
320     free(fname);
321   }
322   PetscFunctionReturn(0);
323 }
324 
325 /*@C
326    PetscBinaryWrite - Writes to a binary file.
327 
328    Not Collective
329 
330    Input Parameters:
331 +  fd     - the file
332 .  p      - the buffer
333 .  n      - the number of items to write
334 -  type   - the type of items to read (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)
335 
336    Level: advanced
337 
338    Notes:
339    `PetscBinaryWrite()` uses byte swapping to work on all machines; the files
340    are written using big-endian ordering to the file. On little-endian machines the numbers
341    are converted to the big-endian format when they are written to disk.
342    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
343    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
344    is used.
345 
346    If running with __float128 precision the output is in __float128 unless one uses the -binary_write_double option
347 
348    The Buffer p should be read-write buffer, and not static data.
349    This way, byte-swapping is done in-place, and then the buffer is
350    written to the file.
351 
352    This routine restores the original contents of the buffer, after
353    it is written to the file. This is done by byte-swapping in-place
354    the second time.
355 
356    Because byte-swapping may be done on the values in data it cannot be declared const
357 
358 .seealso: `PetscBinaryRead()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
359           `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
360 @*/
361 PetscErrorCode PetscBinaryWrite(int fd, const void *p, PetscInt n, PetscDataType type) {
362   const char *pp = (char *)p;
363   int         err, wsize;
364   size_t      m = (size_t)n, maxblock = 65536;
365   const void *ptmp  = p;
366   char       *fname = NULL;
367 #if defined(PETSC_USE_REAL___FLOAT128)
368   PetscBool  writedouble = PETSC_FALSE;
369   double    *ppp;
370   PetscReal *pv;
371   PetscInt   i;
372 #endif
373   PetscDataType wtype = type;
374 
375   PetscFunctionBegin;
376   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to write a negative amount of data %" PetscInt_FMT, n);
377   if (!n) PetscFunctionReturn(0);
378 
379   if (type == PETSC_FUNCTION) {
380 #if defined(PETSC_SERIALIZE_FUNCTIONS)
381     const char *fnametmp;
382 #endif
383     m     = 64;
384     fname = (char *)malloc(m * sizeof(char));
385     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
386 #if defined(PETSC_SERIALIZE_FUNCTIONS)
387     PetscCheck(n <= 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only binary view a single function at a time");
388     PetscCall(PetscFPTFind(*(void **)p, &fnametmp));
389     PetscCall(PetscStrncpy(fname, fnametmp, m));
390 #else
391     PetscCall(PetscStrncpy(fname, "", m));
392 #endif
393     wtype = PETSC_CHAR;
394     pp    = (char *)fname;
395     ptmp  = (void *)fname;
396   }
397 
398 #if defined(PETSC_USE_REAL___FLOAT128)
399   PetscCall(PetscOptionsGetBool(NULL, NULL, "-binary_write_double", &writedouble, NULL));
400   /* If using __float128 precision we still write in doubles to file */
401   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
402     wtype = PETSC_DOUBLE;
403     PetscCall(PetscMalloc1(n, &ppp));
404     pv = (PetscReal *)pp;
405     for (i = 0; i < n; i++) ppp[i] = (double)pv[i];
406     pp   = (char *)ppp;
407     ptmp = (char *)ppp;
408   }
409 #endif
410 
411   if (wtype == PETSC_INT) m *= sizeof(PetscInt);
412   else if (wtype == PETSC_SCALAR) m *= sizeof(PetscScalar);
413 #if defined(PETSC_HAVE_COMPLEX)
414   else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
415 #endif
416   else if (wtype == PETSC_REAL) m *= sizeof(PetscReal);
417   else if (wtype == PETSC_DOUBLE) m *= sizeof(double);
418   else if (wtype == PETSC_FLOAT) m *= sizeof(float);
419   else if (wtype == PETSC_SHORT) m *= sizeof(short);
420   else if (wtype == PETSC_LONG) m *= sizeof(long);
421   else if (wtype == PETSC_CHAR) m *= sizeof(char);
422   else if (wtype == PETSC_ENUM) m *= sizeof(PetscEnum);
423   else if (wtype == PETSC_BOOL) m *= sizeof(PetscBool);
424   else if (wtype == PETSC_INT64) m *= sizeof(PetscInt64);
425   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m) * sizeof(char);
426   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown type");
427 
428   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap((void *)ptmp, wtype, n));
429 
430   while (m) {
431     wsize = (m < maxblock) ? m : maxblock;
432     err   = write(fd, pp, wsize);
433     if (err < 0 && errno == EINTR) continue;
434     PetscCheck(err == wsize, PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE, "Error writing to file total size %d err %d wsize %d", (int)n, (int)err, (int)wsize);
435     m -= wsize;
436     pp += wsize;
437   }
438 
439   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap((void *)ptmp, wtype, n));
440 
441   if (type == PETSC_FUNCTION) free(fname);
442 #if defined(PETSC_USE_REAL___FLOAT128)
443   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) PetscCall(PetscFree(ppp));
444 #endif
445   PetscFunctionReturn(0);
446 }
447 
448 /*@C
449    PetscBinaryOpen - Opens a PETSc binary file.
450 
451    Not Collective
452 
453    Input Parameters:
454 +  name - filename
455 -  mode - open mode of binary file, one of `FILE_MODE_READ`, `FILE_MODE_WRITE`, `FILE_MODE_APPEND``
456 
457    Output Parameter:
458 .  fd - the file
459 
460    Level: advanced
461 
462    Note:
463     Files access with PetscBinaryRead()` and `PetscBinaryWrite()` are ALWAYS written in
464    big-endian format. This means the file can be accessed using `PetscBinaryOpen()` and
465    `PetscBinaryRead()` and `PetscBinaryWrite()` on any machine.
466 
467 .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscFileMode`, `PetscViewerFileSetMode()`, `PetscViewerBinaryGetDescriptor()`,
468           `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
469 @*/
470 PetscErrorCode PetscBinaryOpen(const char name[], PetscFileMode mode, int *fd) {
471   PetscFunctionBegin;
472   switch (mode) {
473   case FILE_MODE_READ: *fd = open(name, O_BINARY | O_RDONLY, 0); break;
474   case FILE_MODE_WRITE: *fd = open(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666); break;
475   case FILE_MODE_APPEND: *fd = open(name, O_BINARY | O_WRONLY | O_APPEND, 0); break;
476   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[mode]);
477   }
478   PetscCheck(*fd != -1, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open file %s for %s", name, PetscFileModes[mode]);
479   PetscFunctionReturn(0);
480 }
481 
482 /*@
483    PetscBinaryClose - Closes a PETSc binary file.
484 
485    Not Collective
486 
487    Output Parameter:
488 .  fd - the file
489 
490    Level: advanced
491 
492 .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
493           `PetscBinarySynchronizedSeek()`
494 @*/
495 PetscErrorCode PetscBinaryClose(int fd) {
496   PetscFunctionBegin;
497   PetscCheck(!close(fd), PETSC_COMM_SELF, PETSC_ERR_SYS, "close() failed on file descriptor");
498   PetscFunctionReturn(0);
499 }
500 
501 /*@C
502    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
503 
504    Not Collective
505 
506    Input Parameters:
507 +  fd - the file
508 .  off - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
509             etc. in your calculation rather than sizeof() to compute byte lengths.
510 -  whence - if `PETSC_BINARY_SEEK_SET` then off is an absolute location in the file
511             if `PETSC_BINARY_SEEK_CUR` then off is an offset from the current location
512             if `PETSC_BINARY_SEEK_END` then off is an offset from the end of file
513 
514    Output Parameter:
515 .   offset - new offset in file
516 
517    Level: developer
518 
519    Note:
520    Integers are stored on the file as 32 long, regardless of whether
521    they are stored in the machine as 32 or 64, this means the same
522    binary file may be read on any machine. Hence you CANNOT use `sizeof()`
523    to determine the offset or location.
524 
525 .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
526           `PetscBinarySynchronizedSeek()`
527 @*/
528 PetscErrorCode PetscBinarySeek(int fd, off_t off, PetscBinarySeekType whence, off_t *offset) {
529   int iwhence = 0;
530 
531   PetscFunctionBegin;
532   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
533   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
534   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
535   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown seek location");
536 #if defined(PETSC_HAVE_LSEEK)
537   *offset = lseek(fd, off, iwhence);
538 #elif defined(PETSC_HAVE__LSEEK)
539   *offset = _lseek(fd, (long)off, iwhence);
540 #else
541   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "System does not have a way of seeking on a file");
542 #endif
543   PetscFunctionReturn(0);
544 }
545 
546 /*@C
547    PetscBinarySynchronizedRead - Reads from a binary file.
548 
549    Collective
550 
551    Input Parameters:
552 +  comm - the MPI communicator
553 .  fd - the file descriptor
554 .  num  - the maximum number of items to read
555 -  type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)
556 
557    Output Parameters:
558 +  data - the buffer
559 -  count - the number of items read, optional
560 
561    Level: developer
562 
563    Notes:
564    Does a `PetscBinaryRead()` followed by an `MPI_Bcast()`
565 
566    If count is not provided and the number of items read is less than
567    the maximum number of items to read, then this routine errors.
568 
569    `PetscBinarySynchronizedRead()` uses byte swapping to work on all machines.
570    Integers are stored on the file as 32 long, regardless of whether
571    they are stored in the machine as 32 or 64, this means the same
572    binary file may be read on any machine.
573 
574 .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedWrite()`,
575           `PetscBinarySynchronizedSeek()`
576 @*/
577 PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm, int fd, void *data, PetscInt num, PetscInt *count, PetscDataType type) {
578   PetscMPIInt  rank, size;
579   MPI_Datatype mtype;
580   PetscInt     ibuf[2] = {0, 0};
581   char        *fname   = NULL;
582   void        *fptr    = NULL;
583 
584   PetscFunctionBegin;
585   if (type == PETSC_FUNCTION) {
586     num   = 64;
587     type  = PETSC_CHAR;
588     fname = (char *)malloc(num * sizeof(char));
589     fptr  = data;
590     data  = (void *)fname;
591     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
592   }
593 
594   PetscCallMPI(MPI_Comm_rank(comm, &rank));
595   PetscCallMPI(MPI_Comm_size(comm, &size));
596   if (rank == 0) ibuf[0] = PetscBinaryRead(fd, data, num, count ? &ibuf[1] : NULL, type);
597   PetscCallMPI(MPI_Bcast(ibuf, 2, MPIU_INT, 0, comm));
598   PetscCall((PetscErrorCode)ibuf[0]);
599 
600   /* 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 */
601   if (size > 1) {
602     PetscCall(PetscDataTypeToMPIDataType(type, &mtype));
603     PetscCallMPI(MPI_Bcast(data, count ? ibuf[1] : num, mtype, 0, comm));
604   }
605   if (count) *count = ibuf[1];
606 
607   if (type == PETSC_FUNCTION) {
608 #if defined(PETSC_SERIALIZE_FUNCTIONS)
609     PetscCall(PetscDLLibrarySym(PETSC_COMM_SELF, &PetscDLLibrariesLoaded, NULL, fname, (void **)fptr));
610 #else
611     *(void **)fptr = NULL;
612 #endif
613     free(fname);
614   }
615   PetscFunctionReturn(0);
616 }
617 
618 /*@C
619    PetscBinarySynchronizedWrite - writes to a binary file.
620 
621    Collective
622 
623    Input Parameters:
624 +  comm - the MPI communicator
625 .  fd - the file
626 .  n  - the number of items to write
627 .  p - the buffer
628 -  type - the type of items to write (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)
629 
630    Level: developer
631 
632    Notes:
633    Process 0 does a `PetscBinaryWrite()`
634 
635    `PetscBinarySynchronizedWrite()` uses byte swapping to work on all machines.
636    Integers are stored on the file as 32 long, regardless of whether
637    they are stored in the machine as 32 or 64, this means the same
638    binary file may be read on any machine.
639 
640    Because byte-swapping may be done on the values in data it cannot be declared const
641 
642    WARNING:
643    This is NOT like `PetscSynchronizedFPrintf()`! This routine ignores calls on all but process 0,
644    while `PetscSynchronizedFPrintf()` has all processes print their strings in order.
645 
646 .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedRead()`,
647           `PetscBinarySynchronizedSeek()`
648 @*/
649 PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm, int fd, const void *p, PetscInt n, PetscDataType type) {
650   PetscMPIInt rank;
651 
652   PetscFunctionBegin;
653   PetscCallMPI(MPI_Comm_rank(comm, &rank));
654   if (rank == 0) PetscCall(PetscBinaryWrite(fd, p, n, type));
655   PetscFunctionReturn(0);
656 }
657 
658 /*@C
659    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
660 
661    Input Parameters:
662 +  fd - the file
663 .  whence - if `PETSC_BINARY_SEEK_SET` then size is an absolute location in the file
664             if `PETSC_BINARY_SEEK_CUR` then size is offset from current location
665             if `PETSC_BINARY_SEEK_END` then size is offset from end of file
666 -  off    - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
667             etc. in your calculation rather than `sizeof()` to compute byte lengths.
668 
669    Output Parameter:
670 .   offset - new offset in file
671 
672    Level: developer
673 
674    Note:
675    Integers are stored on the file as 32 long, regardless of whether
676    they are stored in the machine as 32 or 64, this means the same
677    binary file may be read on any machine. Hence you CANNOT use `sizeof()`
678    to determine the offset or location.
679 
680 .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
681           `PetscBinarySynchronizedSeek()`
682 @*/
683 PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm, int fd, off_t off, PetscBinarySeekType whence, off_t *offset) {
684   PetscMPIInt rank;
685 
686   PetscFunctionBegin;
687   PetscCallMPI(MPI_Comm_rank(comm, &rank));
688   if (rank == 0) PetscCall(PetscBinarySeek(fd, off, whence, offset));
689   PetscFunctionReturn(0);
690 }
691 
692 #if defined(PETSC_HAVE_MPIIO)
693 
694 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
695 /*
696       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
697     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
698 
699     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
700 
701     The next three routines are not used because MPICH does not support their use
702 
703 */
704 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype, MPI_Aint *file_extent, void *extra_state) {
705   MPI_Aint    ub;
706   PetscMPIInt ierr;
707 
708   ierr = MPI_Type_get_extent(datatype, &ub, file_extent);
709   return ierr;
710 }
711 
712 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state) {
713   PetscDataType pdtype;
714   PetscMPIInt   ierr;
715   size_t        dsize;
716 
717   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
718   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));
719 
720   /* offset is given in units of MPI_Datatype */
721   userbuf = ((char *)userbuf) + dsize * position;
722 
723   PetscCall(PetscMemcpy(userbuf, filebuf, count * dsize));
724   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(userbuf, pdtype, count));
725   return ierr;
726 }
727 
728 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state) {
729   PetscDataType pdtype;
730   PetscMPIInt   ierr;
731   size_t        dsize;
732 
733   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
734   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));
735 
736   /* offset is given in units of MPI_Datatype */
737   userbuf = ((char *)userbuf) + dsize * position;
738 
739   PetscCall(PetscMemcpy(filebuf, userbuf, count * dsize));
740   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(filebuf, pdtype, count));
741   return ierr;
742 }
743 #endif
744 
745 PetscErrorCode MPIU_File_write_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status) {
746   PetscDataType pdtype;
747 
748   PetscFunctionBegin;
749   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
750   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
751   PetscCallMPI(MPI_File_write_all(fd, data, cnt, dtype, status));
752   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
753   PetscFunctionReturn(0);
754 }
755 
756 PetscErrorCode MPIU_File_read_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status) {
757   PetscDataType pdtype;
758 
759   PetscFunctionBegin;
760   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
761   PetscCallMPI(MPI_File_read_all(fd, data, cnt, dtype, status));
762   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
763   PetscFunctionReturn(0);
764 }
765 
766 PetscErrorCode MPIU_File_write_at(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status) {
767   PetscDataType pdtype;
768 
769   PetscFunctionBegin;
770   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
771   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
772   PetscCallMPI(MPI_File_write_at(fd, off, data, cnt, dtype, status));
773   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
774   PetscFunctionReturn(0);
775 }
776 
777 PetscErrorCode MPIU_File_read_at(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status) {
778   PetscDataType pdtype;
779 
780   PetscFunctionBegin;
781   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
782   PetscCallMPI(MPI_File_read_at(fd, off, data, cnt, dtype, status));
783   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
784   PetscFunctionReturn(0);
785 }
786 
787 PetscErrorCode MPIU_File_write_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status) {
788   PetscDataType pdtype;
789 
790   PetscFunctionBegin;
791   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
792   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
793   PetscCallMPI(MPI_File_write_at_all(fd, off, data, cnt, dtype, status));
794   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
795   PetscFunctionReturn(0);
796 }
797 
798 PetscErrorCode MPIU_File_read_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status) {
799   PetscDataType pdtype;
800 
801   PetscFunctionBegin;
802   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
803   PetscCallMPI(MPI_File_read_at_all(fd, off, data, cnt, dtype, status));
804   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
805   PetscFunctionReturn(0);
806 }
807 
808 #endif
809