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