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 = (PetscReal *)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: PetscReal tmp, *buff1 = (PetscReal *)buff;
173: char *ptr1, *ptr2 = (char *)&tmp;
175: PetscFunctionBegin;
176: #if defined(PETSC_USE_COMPLEX)
177: n *= 2;
178: #endif
179: for (j = 0; j < n; j++) {
180: ptr1 = (char *)(buff1 + j);
181: for (i = 0; i < (PetscCount)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i];
182: for (i = 0; i < (PetscCount)sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
183: }
184: PetscFunctionReturn(PETSC_SUCCESS);
185: }
187: /*
188: PetscByteSwapDouble - Swap bytes in a double
189: */
190: static PetscErrorCode PetscByteSwapDouble(double *buff, PetscCount n)
191: {
192: PetscCount i, j;
193: double tmp, *buff1 = (double *)buff;
194: char *ptr1, *ptr2 = (char *)&tmp;
196: PetscFunctionBegin;
197: for (j = 0; j < n; j++) {
198: ptr1 = (char *)(buff1 + j);
199: for (i = 0; i < (PetscCount)sizeof(double); i++) ptr2[i] = ptr1[sizeof(double) - 1 - i];
200: for (i = 0; i < (PetscCount)sizeof(double); i++) ptr1[i] = ptr2[i];
201: }
202: PetscFunctionReturn(PETSC_SUCCESS);
203: }
205: /*
206: PetscByteSwapFloat - Swap bytes in a float
207: */
208: static PetscErrorCode PetscByteSwapFloat(float *buff, PetscCount n)
209: {
210: PetscCount i, j;
211: float tmp, *buff1 = (float *)buff;
212: char *ptr1, *ptr2 = (char *)&tmp;
214: PetscFunctionBegin;
215: for (j = 0; j < n; j++) {
216: ptr1 = (char *)(buff1 + j);
217: for (i = 0; i < (PetscCount)sizeof(float); i++) ptr2[i] = ptr1[sizeof(float) - 1 - i];
218: for (i = 0; i < (PetscCount)sizeof(float); i++) ptr1[i] = ptr2[i];
219: }
220: PetscFunctionReturn(PETSC_SUCCESS);
221: }
223: PetscErrorCode PetscByteSwap(void *data, PetscDataType pdtype, PetscCount count)
224: {
225: PetscFunctionBegin;
226: if (pdtype == PETSC_INT) PetscCall(PetscByteSwapInt((PetscInt *)data, count));
227: else if (pdtype == PETSC_ENUM) PetscCall(PetscByteSwapEnum((PetscEnum *)data, count));
228: else if (pdtype == PETSC_BOOL) PetscCall(PetscByteSwapBool((PetscBool *)data, count));
229: else if (pdtype == PETSC_SCALAR) PetscCall(PetscByteSwapScalar((PetscScalar *)data, count));
230: else if (pdtype == PETSC_REAL) PetscCall(PetscByteSwapReal((PetscReal *)data, count));
231: else if (pdtype == PETSC_COMPLEX) PetscCall(PetscByteSwapReal((PetscReal *)data, 2 * count));
232: else if (pdtype == PETSC_INT64) PetscCall(PetscByteSwapInt64((PetscInt64 *)data, count));
233: else if (pdtype == PETSC_COUNT) PetscCall(PetscByteSwapInt64((PetscInt64 *)data, count));
234: else if (pdtype == PETSC_INT32) PetscCall(PetscByteSwapInt32((PetscInt32 *)data, count));
235: else if (pdtype == PETSC_DOUBLE) PetscCall(PetscByteSwapDouble((double *)data, count));
236: else if (pdtype == PETSC_FLOAT) PetscCall(PetscByteSwapFloat((float *)data, count));
237: else if (pdtype == PETSC_SHORT) PetscCall(PetscByteSwapShort((short *)data, count));
238: else if (pdtype == PETSC_LONG) PetscCall(PetscByteSwapLong((long *)data, count));
239: else if (pdtype == PETSC_CHAR) PetscFunctionReturn(PETSC_SUCCESS);
240: else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown type: %d", pdtype);
241: PetscFunctionReturn(PETSC_SUCCESS);
242: }
244: /*@C
245: PetscBinaryRead - Reads from a binary file.
247: Not Collective
249: Input Parameters:
250: + fd - the file descriptor
251: . num - the maximum number of items to read
252: - type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)
254: Output Parameters:
255: + data - the buffer, this is an array of the type that matches the value in `type`
256: - count - the number of items read, optional
258: Level: developer
260: Notes:
261: If `count` is not provided and the number of items read is less than
262: the maximum number of items to read, then this routine errors.
264: `PetscBinaryRead()` uses byte swapping to work on all machines; the files
265: are written ALWAYS using big-endian ordering. On little-endian machines the numbers
266: are converted to the little-endian format when they are read in from the file.
267: When PETSc is ./configure with `--with-64-bit-indices` the integers are written to the
268: file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices`
269: is used.
271: Fortran Note:
272: There are different functions for each datatype, for example `PetscBinaryReadInt()`
274: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
275: `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
276: @*/
277: PetscErrorCode PetscBinaryRead(int fd, void *data, PetscCount num, PetscInt *count, PetscDataType type)
278: {
279: size_t typesize, m = (size_t)num, n = 0, maxblock = 65536;
280: char *p = (char *)data;
281: #if defined(PETSC_USE_REAL___FLOAT128)
282: PetscBool readdouble = PETSC_FALSE;
283: double *pdouble;
284: #endif
285: void *ptmp = data;
286: char *fname = NULL;
288: PetscFunctionBegin;
289: if (count) *count = 0;
290: PetscCheck(num >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to read a negative amount of data %" PetscCount_FMT, num);
291: if (!num) PetscFunctionReturn(PETSC_SUCCESS);
293: if (type == PETSC_FUNCTION) {
294: m = 64;
295: type = PETSC_CHAR;
296: fname = (char *)malloc(m * sizeof(char));
297: p = (char *)fname;
298: ptmp = (void *)fname;
299: PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
300: }
301: if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(num);
303: PetscCall(PetscDataTypeGetSize(type, &typesize));
305: #if defined(PETSC_USE_REAL___FLOAT128)
306: PetscCall(PetscOptionsGetBool(NULL, NULL, "-binary_read_double", &readdouble, NULL));
307: /* If using __float128 precision we still read in doubles from file */
308: if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
309: PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
310: PetscCall(PetscMalloc1(cnt, &pdouble));
311: p = (char *)pdouble;
312: typesize /= 2;
313: }
314: #endif
316: m *= typesize;
318: while (m) {
319: size_t len = (m < maxblock) ? m : maxblock;
320: int ret = (int)read(fd, p, len);
321: if (ret < 0 && errno == EINTR) continue;
322: if (!ret && len > 0) break; /* Proxy for EOF */
323: PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file due to \"%s\"", strerror(errno));
324: m -= (size_t)ret;
325: p += ret;
326: n += (size_t)ret;
327: }
328: PetscCheck(!m || count, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Read past end of file");
330: num = n / typesize; /* Should we require `n % typesize == 0` ? */
331: if (count) PetscCall(PetscIntCast(num, count)); /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */
333: #if defined(PETSC_USE_REAL___FLOAT128)
334: if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
335: PetscInt i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
336: PetscReal *preal = (PetscReal *)data;
337: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwapDouble(pdouble, cnt));
338: for (i = 0; i < cnt; i++) preal[i] = pdouble[i];
339: PetscCall(PetscFree(pdouble));
340: PetscFunctionReturn(PETSC_SUCCESS);
341: }
342: #endif
344: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(ptmp, type, num));
346: if (type == PETSC_FUNCTION) {
347: #if defined(PETSC_SERIALIZE_FUNCTIONS)
348: PetscCall(PetscDLSym(NULL, fname, (void **)data));
349: #else
350: *(void **)data = NULL;
351: #endif
352: free(fname);
353: }
354: PetscFunctionReturn(PETSC_SUCCESS);
355: }
357: /*@C
358: PetscBinaryWrite - Writes to a binary file.
360: Not Collective
362: Input Parameters:
363: + fd - the file
364: . p - the buffer, an array of the type that matches the value in `type`
365: . n - the number of items to write
366: - type - the type of items to read (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)
368: Level: advanced
370: Notes:
371: `PetscBinaryWrite()` uses byte swapping to work on all machines; the files
372: are written using big-endian ordering to the file. On little-endian machines the numbers
373: are converted to the big-endian format when they are written to disk.
374: When PETSc is configured using `./configure with --with-64-bit-indices` the integers are written to the
375: file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices`
376: is used.
378: If running with `__float128` precision the output of `PETSC_REAL` is in `__float128` unless one uses the `-binary_write_double` option
380: The buffer `p` should be read-write buffer, and not static data.
381: This way, byte-swapping is done in-place, and then the buffer is
382: written to the file.
384: This routine restores the original contents of the buffer, after
385: it is written to the file. This is done by byte-swapping in-place
386: the second time.
388: Because byte-swapping may be done on the values in data it cannot be declared const
390: Fortran Note:
391: There are different functions for each datatype, for example `PetscBinaryWriteInt()`
393: .seealso: `PetscBinaryRead()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
394: `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
395: @*/
396: PetscErrorCode PetscBinaryWrite(int fd, const void *p, PetscCount n, PetscDataType type)
397: {
398: const char *pp = (char *)p;
399: size_t err, m = (size_t)n, wsize;
400: const size_t maxblock = 65536;
401: const void *ptmp = p;
402: char *fname = NULL;
403: #if defined(PETSC_USE_REAL___FLOAT128)
404: PetscBool writedouble = PETSC_FALSE;
405: double *ppp;
406: PetscReal *pv;
407: #endif
408: PetscDataType wtype = type;
410: PetscFunctionBegin;
411: PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to write a negative amount of data %" PetscCount_FMT, n);
412: if (!n) PetscFunctionReturn(PETSC_SUCCESS);
414: if (type == PETSC_FUNCTION) {
415: #if defined(PETSC_SERIALIZE_FUNCTIONS)
416: const char *fnametmp;
417: #endif
418: m = 64;
419: fname = (char *)malloc(m * sizeof(char));
420: PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
421: #if defined(PETSC_SERIALIZE_FUNCTIONS)
422: PetscCheck(n <= 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only binary view a single function at a time");
423: PetscCall(PetscFPTFind(*(void **)p, &fnametmp));
424: PetscCall(PetscStrncpy(fname, fnametmp, m));
425: #else
426: PetscCall(PetscStrncpy(fname, "", m));
427: #endif
428: wtype = PETSC_CHAR;
429: pp = (char *)fname;
430: ptmp = (void *)fname;
431: }
433: #if defined(PETSC_USE_REAL___FLOAT128)
434: PetscCall(PetscOptionsGetBool(NULL, NULL, "-binary_write_double", &writedouble, NULL));
435: /* If using __float128 precision we still write in doubles to file */
436: if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
437: wtype = PETSC_DOUBLE;
438: PetscCall(PetscMalloc1(n, &ppp));
439: pv = (PetscReal *)pp;
440: for (PetscCount i = 0; i < n; i++) ppp[i] = (double)pv[i];
441: pp = (char *)ppp;
442: ptmp = (char *)ppp;
443: }
444: #endif
446: if (wtype == PETSC_INT) m *= sizeof(PetscInt);
447: else if (wtype == PETSC_SCALAR) m *= sizeof(PetscScalar);
448: #if defined(PETSC_HAVE_COMPLEX)
449: else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
450: #endif
451: else if (wtype == PETSC_REAL) m *= sizeof(PetscReal);
452: else if (wtype == PETSC_DOUBLE) m *= sizeof(double);
453: else if (wtype == PETSC_FLOAT) m *= sizeof(float);
454: else if (wtype == PETSC_SHORT) m *= sizeof(short);
455: else if (wtype == PETSC_LONG) m *= sizeof(long);
456: else if (wtype == PETSC_CHAR) m *= sizeof(char);
457: else if (wtype == PETSC_ENUM) m *= sizeof(PetscEnum);
458: else if (wtype == PETSC_BOOL) m *= sizeof(PetscBool);
459: else if (wtype == PETSC_INT64) m *= sizeof(PetscInt64);
460: else if (wtype == PETSC_INT32) m *= sizeof(PetscInt32);
461: else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m) * sizeof(char);
462: else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown type: %d", wtype);
464: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap((void *)ptmp, wtype, n));
466: while (m) {
467: wsize = (m < maxblock) ? m : maxblock;
468: err = (size_t)write(fd, pp, wsize);
469: if (errno == EINTR) continue;
470: 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));
471: m -= wsize;
472: pp += wsize;
473: }
475: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap((void *)ptmp, wtype, n));
477: if (type == PETSC_FUNCTION) free(fname);
478: #if defined(PETSC_USE_REAL___FLOAT128)
479: if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) PetscCall(PetscFree(ppp));
480: #endif
481: PetscFunctionReturn(PETSC_SUCCESS);
482: }
484: /*@
485: PetscBinaryOpen - Opens a PETSc binary file.
487: Not Collective
489: Input Parameters:
490: + name - filename
491: - mode - open mode of binary file, one of `FILE_MODE_READ`, `FILE_MODE_WRITE`, `FILE_MODE_APPEND`
493: Output Parameter:
494: . fd - the file
496: Level: advanced
498: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscFileMode`, `PetscViewerFileSetMode()`, `PetscViewerBinaryGetDescriptor()`,
499: `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
500: @*/
501: PetscErrorCode PetscBinaryOpen(const char name[], PetscFileMode mode, int *fd)
502: {
503: PetscFunctionBegin;
504: switch (mode) {
505: case FILE_MODE_READ:
506: *fd = open(name, O_BINARY | O_RDONLY, 0);
507: break;
508: case FILE_MODE_WRITE:
509: *fd = open(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
510: break;
511: case FILE_MODE_APPEND:
512: *fd = open(name, O_BINARY | O_WRONLY | O_APPEND, 0);
513: break;
514: default:
515: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[mode]);
516: }
517: PetscCheck(*fd != -1, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open file %s for %s due to \"%s\"", name, PetscFileModes[mode], strerror(errno));
518: PetscFunctionReturn(PETSC_SUCCESS);
519: }
521: /*@
522: PetscBinaryClose - Closes a PETSc binary file.
524: Not Collective
526: Output Parameter:
527: . fd - the file
529: Level: advanced
531: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
532: `PetscBinarySynchronizedSeek()`
533: @*/
534: PetscErrorCode PetscBinaryClose(int fd)
535: {
536: PetscFunctionBegin;
537: PetscCheck(!close(fd), PETSC_COMM_SELF, PETSC_ERR_SYS, "close() failed on file descriptor");
538: PetscFunctionReturn(PETSC_SUCCESS);
539: }
541: /*@C
542: PetscBinarySeek - Moves the file pointer on a PETSc binary file.
544: Not Collective, No Fortran Support
546: Input Parameters:
547: + fd - the file
548: . off - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
549: etc. in your calculation rather than `sizeof()` to compute byte lengths.
550: - whence - see `PetscBinarySeekType` for possible values
552: Output Parameter:
553: . offset - new offset in file
555: Level: developer
557: .seealso: `PetscBinaryRead()`, `PetscBinarySeekType`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
558: `PetscBinarySynchronizedSeek()`
559: @*/
560: PetscErrorCode PetscBinarySeek(int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
561: {
562: int iwhence = 0;
564: PetscFunctionBegin;
565: if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
566: else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
567: else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
568: else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown seek location");
569: #if defined(PETSC_HAVE_LSEEK)
570: *offset = lseek(fd, off, iwhence);
571: #elif defined(PETSC_HAVE__LSEEK)
572: *offset = _lseek(fd, (long)off, iwhence);
573: #else
574: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "System does not have a way of seeking on a file");
575: #endif
576: PetscFunctionReturn(PETSC_SUCCESS);
577: }
579: /*@C
580: PetscBinarySynchronizedRead - Reads from a binary file, all MPI processes get the same values
582: Collective, No Fortran Support
584: Input Parameters:
585: + comm - the MPI communicator
586: . fd - the file descriptor
587: . num - the maximum number of items to read
588: - type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)
590: Output Parameters:
591: + data - the buffer, an array of the type that matches the value in `type`
592: - count - the number of items read, optional
594: Level: developer
596: Notes:
597: Does a `PetscBinaryRead()` followed by an `MPI_Bcast()`
599: If `count` is not provided and the number of items read is less than
600: the maximum number of items to read, then this routine errors.
602: `PetscBinarySynchronizedRead()` uses byte swapping to work on all machines.
603: The files are written using big-endian ordering to the file. On little-endian machines the numbers
604: are converted to the big-endian format when they are written to disk.
605: When PETSc is configured using `./configure with --with-64-bit-indices` the integers are written to the
606: file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices`
607: is used.
609: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedWrite()`,
610: `PetscBinarySynchronizedSeek()`
611: @*/
612: PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm, int fd, void *data, PetscInt num, PetscInt *count, PetscDataType type)
613: {
614: PetscMPIInt rank, size;
615: MPI_Datatype mtype;
616: PetscInt ibuf[2] = {0, 0};
617: char *fname = NULL;
618: void *fptr = NULL;
620: PetscFunctionBegin;
621: if (type == PETSC_FUNCTION) {
622: num = 64;
623: type = PETSC_CHAR;
624: fname = (char *)malloc(num * sizeof(char));
625: fptr = data;
626: data = (void *)fname;
627: PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
628: }
630: PetscCallMPI(MPI_Comm_rank(comm, &rank));
631: PetscCallMPI(MPI_Comm_size(comm, &size));
632: if (rank == 0) ibuf[0] = (PetscInt)PetscBinaryRead(fd, data, num, count ? &ibuf[1] : NULL, type);
633: PetscCallMPI(MPI_Bcast(ibuf, 2, MPIU_INT, 0, comm));
634: PetscCall((PetscErrorCode)ibuf[0]);
636: /* 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 */
637: if (size > 1) {
638: PetscMPIInt cnt;
640: PetscCall(PetscMPIIntCast(count ? ibuf[1] : num, &cnt));
641: PetscCall(PetscDataTypeToMPIDataType(type, &mtype));
642: PetscCallMPI(MPI_Bcast(data, cnt, mtype, 0, comm));
643: }
644: if (count) *count = ibuf[1];
646: if (type == PETSC_FUNCTION) {
647: #if defined(PETSC_SERIALIZE_FUNCTIONS)
648: PetscCall(PetscDLLibrarySym(PETSC_COMM_SELF, &PetscDLLibrariesLoaded, NULL, fname, (void **)fptr));
649: #else
650: *(void **)fptr = NULL;
651: #endif
652: free(fname);
653: }
654: PetscFunctionReturn(PETSC_SUCCESS);
655: }
657: /*@C
658: PetscBinarySynchronizedWrite - writes to a binary file.
660: Collective, No Fortran Support
662: Input Parameters:
663: + comm - the MPI communicator
664: . fd - the file
665: . n - the number of items to write
666: . p - the buffer, an array of the type that matches the value in `type`
667: - type - the type of items to write (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)
669: Level: developer
671: Notes:
672: MPI rank 0 does a `PetscBinaryWrite()` the values on other MPI processes are not used
674: The files are written using big-endian ordering to the file. On little-endian machines the numbers
675: are converted to the big-endian format when they are written to disk.
676: When PETSc is configured using `./configure with --with-64-bit-indices` the integers are written to the
677: file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices`
678: is used.
680: Because byte-swapping may be done on the values in data it cannot be declared const
682: This is NOT like `PetscSynchronizedFPrintf()`! This routine ignores calls on all but MPI rank 0,
683: while `PetscSynchronizedFPrintf()` has all MPI processes print their strings in order.
685: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedRead()`,
686: `PetscBinarySynchronizedSeek()`
687: @*/
688: PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm, int fd, const void *p, PetscInt n, PetscDataType type)
689: {
690: PetscMPIInt rank;
692: PetscFunctionBegin;
693: PetscCallMPI(MPI_Comm_rank(comm, &rank));
694: if (rank == 0) PetscCall(PetscBinaryWrite(fd, p, n, type));
695: PetscFunctionReturn(PETSC_SUCCESS);
696: }
698: /*@C
699: PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
701: No Fortran Support
703: Input Parameters:
704: + comm - the communicator to read with
705: . fd - the file
706: . whence - see `PetscBinarySeekType` for possible values
707: - off - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
708: etc. in your calculation rather than `sizeof()` to compute byte lengths.
710: Output Parameter:
711: . offset - new offset in file
713: Level: developer
715: .seealso: `PetscBinaryRead()`, `PetscBinarySeekType`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
717: @*/
718: PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm, int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
719: {
720: PetscMPIInt rank;
722: PetscFunctionBegin;
723: PetscCallMPI(MPI_Comm_rank(comm, &rank));
724: if (rank == 0) PetscCall(PetscBinarySeek(fd, off, whence, offset));
725: PetscFunctionReturn(PETSC_SUCCESS);
726: }
728: #if defined(PETSC_HAVE_MPIIO)
730: #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
731: /*
732: MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
733: These are set into MPI in PetscInitialize() via MPI_Register_datarep()
735: Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
737: The next three routines are not used because MPICH does not support their use
739: */
740: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype, MPI_Aint *file_extent, void *extra_state)
741: {
742: MPI_Aint ub;
743: PetscMPIInt ierr;
745: ierr = MPI_Type_get_extent(datatype, &ub, file_extent);
746: return ierr;
747: }
749: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
750: {
751: PetscDataType pdtype;
752: PetscMPIInt ierr;
753: size_t dsize;
755: PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
756: PetscCall(PetscDataTypeGetSize(pdtype, &dsize));
758: /* offset is given in units of MPI_Datatype */
759: userbuf = ((char *)userbuf) + dsize * position;
761: PetscCall(PetscMemcpy(userbuf, filebuf, count * dsize));
762: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(userbuf, pdtype, count));
763: return ierr;
764: }
766: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
767: {
768: PetscDataType pdtype;
769: PetscMPIInt ierr;
770: size_t dsize;
772: PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
773: PetscCall(PetscDataTypeGetSize(pdtype, &dsize));
775: /* offset is given in units of MPI_Datatype */
776: userbuf = ((char *)userbuf) + dsize * position;
778: PetscCall(PetscMemcpy(filebuf, userbuf, count * dsize));
779: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(filebuf, pdtype, count));
780: return ierr;
781: }
782: #endif
784: PetscErrorCode MPIU_File_write_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
785: {
786: PetscDataType pdtype;
788: PetscFunctionBegin;
789: PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
790: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
791: PetscCallMPI(MPI_File_write_all(fd, data, cnt, dtype, status));
792: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
793: PetscFunctionReturn(PETSC_SUCCESS);
794: }
796: PetscErrorCode MPIU_File_read_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
797: {
798: PetscDataType pdtype;
800: PetscFunctionBegin;
801: PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
802: PetscCallMPI(MPI_File_read_all(fd, data, cnt, dtype, status));
803: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
804: PetscFunctionReturn(PETSC_SUCCESS);
805: }
807: PetscErrorCode MPIU_File_write_at(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
808: {
809: PetscDataType pdtype;
811: PetscFunctionBegin;
812: PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
813: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
814: PetscCallMPI(MPI_File_write_at(fd, off, data, cnt, dtype, status));
815: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
816: PetscFunctionReturn(PETSC_SUCCESS);
817: }
819: PetscErrorCode MPIU_File_read_at(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
820: {
821: PetscDataType pdtype;
823: PetscFunctionBegin;
824: PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
825: PetscCallMPI(MPI_File_read_at(fd, off, data, cnt, dtype, status));
826: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
827: PetscFunctionReturn(PETSC_SUCCESS);
828: }
830: PetscErrorCode MPIU_File_write_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
831: {
832: PetscDataType pdtype;
834: PetscFunctionBegin;
835: PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
836: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
837: PetscCallMPI(MPI_File_write_at_all(fd, off, data, cnt, dtype, status));
838: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
839: PetscFunctionReturn(PETSC_SUCCESS);
840: }
842: PetscErrorCode MPIU_File_read_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
843: {
844: PetscDataType pdtype;
846: PetscFunctionBegin;
847: PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
848: PetscCallMPI(MPI_File_read_at_all(fd, off, data, cnt, dtype, status));
849: if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
850: PetscFunctionReturn(PETSC_SUCCESS);
851: }
853: #endif