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