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