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