Actual source code: sysio.c
1: #define PETSC_DLL
3: /*
4: This file contains simple binary read/write routines.
5: */
7: #include petsc.h
8: #include petscsys.h
10: #include <errno.h>
11: #include <fcntl.h>
12: #if defined(PETSC_HAVE_UNISTD_H)
13: #include <unistd.h>
14: #endif
15: #if defined (PETSC_HAVE_IO_H)
16: #include <io.h>
17: #endif
18: #include petscbt.h
20: #if (PETSC_SIZEOF_INT == 8)
21: #define PetscInt32 short
22: #else
23: #define PetscInt32 int
24: #endif
26: #if !defined(PETSC_WORDS_BIGENDIAN)
30: /*
31: PetscByteSwapInt - Swap bytes in a 32 bit integer. NOT a PetscInt! Note that PETSc binary read and write
32: always store and read only 32 bit integers! (See PetscBinaryRead(), PetscBinaryWrite()).
34: */
35: PetscErrorCode PetscByteSwapInt(PetscInt32 *buff,PetscInt n)
36: {
37: PetscInt i,j,tmp = 0;
38: PetscInt *tptr = &tmp; /* Need to access tmp indirectly to get */
39: char *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
40:
42: for (j=0; j<n; j++) {
43: ptr1 = (char*)(buff + j);
44: for (i=0; i<(int)sizeof(PetscInt32); i++) {
45: ptr2[i] = ptr1[sizeof(PetscInt32)-1-i];
46: }
47: buff[j] = *tptr;
48: }
49: return(0);
50: }
51: /* --------------------------------------------------------- */
54: /*
55: PetscByteSwapShort - Swap bytes in a short
56: */
57: PetscErrorCode PetscByteSwapShort(short *buff,PetscInt n)
58: {
59: PetscInt i,j;
60: short tmp;
61: short *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
62: char *ptr1,*ptr2 = (char*)&tmp;
65: for (j=0; j<n; j++) {
66: ptr1 = (char*)(buff + j);
67: for (i=0; i<(int) sizeof(short); i++) {
68: ptr2[i] = ptr1[sizeof(int)-1-i];
69: }
70: buff[j] = *tptr;
71: }
72: return(0);
73: }
74: /* --------------------------------------------------------- */
77: /*
78: PetscByteSwapScalar - Swap bytes in a double
79: Complex is dealt with as if array of double twice as long.
80: */
81: PetscErrorCode PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
82: {
83: PetscInt i,j;
84: PetscReal tmp,*buff1 = (PetscReal*)buff;
85: PetscReal *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
86: char *ptr1,*ptr2 = (char*)&tmp;
89: #if defined(PETSC_USE_COMPLEX)
90: n *= 2;
91: #endif
92: for (j=0; j<n; j++) {
93: ptr1 = (char*)(buff1 + j);
94: for (i=0; i<(int) sizeof(PetscReal); i++) {
95: ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
96: }
97: buff1[j] = *tptr;
98: }
99: return(0);
100: }
101: /* --------------------------------------------------------- */
104: /*
105: PetscByteSwapDouble - Swap bytes in a double
106: */
107: PetscErrorCode PetscByteSwapDouble(double *buff,PetscInt n)
108: {
109: PetscInt i,j;
110: double tmp,*buff1 = (double*)buff;
111: double *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
112: char *ptr1,*ptr2 = (char*)&tmp;
115: for (j=0; j<n; j++) {
116: ptr1 = (char*)(buff1 + j);
117: for (i=0; i<(int) sizeof(double); i++) {
118: ptr2[i] = ptr1[sizeof(double)-1-i];
119: }
120: buff1[j] = *tptr;
121: }
122: return(0);
123: }
124: #endif
125: /* --------------------------------------------------------- */
128: /*@
129: PetscBinaryRead - Reads from a binary file.
131: Not Collective
133: Input Parameters:
134: + fd - the file
135: . n - the number of items to read
136: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
138: Output Parameters:
139: . p - the buffer
143: Level: developer
145: Notes:
146: PetscBinaryRead() uses byte swapping to work on all machines; the files
147: are written to file ALWAYS using big-endian ordering. On small-endian machines the numbers
148: are converted to the small-endian format when they are read in from the file.
149: Integers are stored on the file as 32 bits long, regardless of whether
150: they are stored in the machine as 32 bits or 64 bits, this means the same
151: binary file may be read on any machine.
153: Concepts: files^reading binary
154: Concepts: binary files^reading
156: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor()
157: @*/
158: PetscErrorCode PetscBinaryRead(int fd,void *p,PetscInt n,PetscDataType type)
159: {
160: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES) || !defined(PETSC_WORDS_BIGENDIAN)
161: PetscErrorCode ierr;
162: #endif
163: int wsize,err;
164: size_t m = (size_t) n,maxblock = 65536;
165: char *pp = (char*)p;
166: #if (PETSC_SIZEOF_INT == 8) || !defined(PETSC_WORDS_BIGENDIAN) || defined(PETSC_USE_64BIT_INDICES)
167: void *ptmp = p;
168: #endif
171: if (!n) return(0);
173: if (type == PETSC_INT){
174: m *= sizeof(PetscInt32);
175: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
176: /* read them in as 32 bit ints, later stretch into ints */
177: PetscMalloc(m,&pp);
178: ptmp = (void*)pp;
179: #endif
180: }
181: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
182: else if (type == PETSC_DOUBLE) m *= sizeof(double);
183: else if (type == PETSC_SHORT) m *= sizeof(short);
184: else if (type == PETSC_CHAR) m *= sizeof(char);
185: else if (type == PETSC_ENUM) m *= sizeof(PetscEnum);
186: else if (type == PETSC_TRUTH) m *= sizeof(PetscTruth);
187: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
188: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
189:
190: while (m) {
191: wsize = (m < maxblock) ? m : maxblock;
192: err = read(fd,pp,wsize);
193: if (err < 0 && errno == EINTR) continue;
194: if (!err && wsize > 0) SETERRQ(PETSC_ERR_FILE_READ,"Read past end of file");
195: if (err < 0) SETERRQ(PETSC_ERR_FILE_READ,"Error reading from file");
196: m -= err;
197: pp += err;
198: }
199: #if !defined(PETSC_WORDS_BIGENDIAN)
200: if (type == PETSC_INT) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
201: else if (type == PETSC_ENUM) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
202: else if (type == PETSC_TRUTH) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
203: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
204: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
205: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
206: #endif
208: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
209: if (type == PETSC_INT) {
210: PetscInt *p_int = (PetscInt*)p,i;
211: PetscInt32 *p_short = (PetscInt32 *)ptmp;
212: for (i=0; i<n; i++) {
213: p_int[i] = (PetscInt)p_short[i];
214: }
215: PetscFree(ptmp);
216: }
217: #endif
218: return(0);
219: }
220: /* --------------------------------------------------------- */
223: /*@
224: PetscBinaryWrite - Writes to a binary file.
226: Not Collective
228: Input Parameters:
229: + fd - the file
230: . p - the buffer
231: . n - the number of items to write
232: . type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
233: - istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.
235: Level: advanced
237: Notes:
238: PetscBinaryWrite() uses byte swapping to work on all machines; the files
239: are written using big-endian ordering to the file. On small-endian machines the numbers
240: are converted to the big-endian format when they are written to disk.
241: Integers are stored on the file as 32 bits long, regardless of whether
242: they are stored in the machine as 32 bits or 64 bits, this means the same
243: binary file may be read on any machine. It also means that 64 bit integers larger than
244: roughly 2 billion are TRUNCATED/WRONG when written to the file.
246: The Buffer p should be read-write buffer, and not static data.
247: This way, byte-swapping is done in-place, and then the buffer is
248: written to the file.
249:
250: This routine restores the original contents of the buffer, after
251: it is written to the file. This is done by byte-swapping in-place
252: the second time. If the flag istemp is set to PETSC_TRUE, the second
253: byte-swapping operation is not done, thus saving some computation,
254: but the buffer corrupted is corrupted.
256: Concepts: files^writing binary
257: Concepts: binary files^writing
259: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor()
260: @*/
261: PetscErrorCode PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
262: {
263: char *pp = (char*)p;
264: int err,wsize;
265: size_t m = (size_t)n,maxblock=65536;
266: #if !defined(PETSC_WORDS_BIGENDIAN) || (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
268: void *ptmp = p;
269: #endif
272: if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
273: if (!n) return(0);
275: if (type == PETSC_INT){
276: m *= sizeof(PetscInt32);
277: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
278: PetscInt *p_int = (PetscInt*)p,i;
279: PetscInt32 *p_short;
280: PetscMalloc(m,&pp);
281: ptmp = (void*)pp;
282: p_short = (PetscInt32*)pp;
284: for (i=0; i<n; i++) {
285: p_short[i] = (PetscInt32) p_int[i];
286: }
287: istemp = PETSC_TRUE;
288: #endif
289: }
290: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
291: else if (type == PETSC_DOUBLE) m *= sizeof(double);
292: else if (type == PETSC_SHORT) m *= sizeof(short);
293: else if (type == PETSC_CHAR) m *= sizeof(char);
294: else if (type == PETSC_ENUM) m *= sizeof(PetscEnum);
295: else if (type == PETSC_TRUTH) m *= sizeof(PetscTruth);
296: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
297: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
299: #if !defined(PETSC_WORDS_BIGENDIAN)
300: if (type == PETSC_INT) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
301: else if (type == PETSC_ENUM) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
302: else if (type == PETSC_TRUTH) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
303: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
304: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
305: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
306: #endif
308: while (m) {
309: wsize = (m < maxblock) ? m : maxblock;
310: err = write(fd,pp,wsize);
311: if (err < 0 && errno == EINTR) continue;
312: if (err != wsize) SETERRQ(PETSC_ERR_FILE_WRITE,"Error writing to file.");
313: m -= wsize;
314: pp += wsize;
315: }
317: #if !defined(PETSC_WORDS_BIGENDIAN) && !(PETSC_SIZEOF_INT == 8) && !defined(PETSC_USE_64BIT_INDICES)
318: if (!istemp) {
319: if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
320: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
321: else if (type == PETSC_INT) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
322: else if (type == PETSC_ENUM) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
323: else if (type == PETSC_TRUTH) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
324: }
325: #endif
327: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
328: if (type == PETSC_INT){
329: PetscFree(ptmp);
330: }
331: #endif
332: return(0);
333: }
337: /*@C
338: PetscBinaryOpen - Opens a PETSc binary file.
340: Not Collective
342: Input Parameters:
343: + name - filename
344: - type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE
346: Output Parameter:
347: . fd - the file
349: Level: advanced
351: Concepts: files^opening binary
352: Concepts: binary files^opening
354: Notes: Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
355: big-endian format. This means the file can be accessed using PetscBinaryOpen() and
356: PetscBinaryRead() and PetscBinaryWrite() on any machine.
358: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor()
360: @*/
361: PetscErrorCode PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
362: {
364: #if defined(PETSC_HAVE_O_BINARY)
365: if (mode == FILE_MODE_WRITE) {
366: if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
367: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
368: }
369: } else if (mode == FILE_MODE_READ) {
370: if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
371: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
372: }
373: } else if (mode == FILE_MODE_APPEND) {
374: if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
375: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
376: }
377: #else
378: if (mode == FILE_MODE_WRITE) {
379: if ((*fd = creat(name,0666)) == -1) {
380: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
381: }
382: } else if (mode == FILE_MODE_READ) {
383: if ((*fd = open(name,O_RDONLY,0)) == -1) {
384: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
385: }
386: }
387: else if (mode == FILE_MODE_APPEND) {
388: if ((*fd = open(name,O_WRONLY,0)) == -1) {
389: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
390: }
391: #endif
392: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
393: return(0);
394: }
398: /*@
399: PetscBinaryClose - Closes a PETSc binary file.
401: Not Collective
403: Output Parameter:
404: . fd - the file
406: Level: advanced
408: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
409: @*/
410: PetscErrorCode PetscBinaryClose(int fd)
411: {
413: close(fd);
414: return(0);
415: }
420: /*@
421: PetscBinarySeek - Moves the file pointer on a PETSc binary file.
423: Not Collective
425: Input Parameters:
426: + fd - the file
427: . off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
428: etc. in your calculation rather than sizeof() to compute byte lengths.
429: - whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
430: if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
431: if PETSC_BINARY_SEEK_END then off is an offset from the end of file
433: Output Parameter:
434: . offset - new offset in file
436: Level: developer
438: Notes:
439: Integers are stored on the file as 32 long, regardless of whether
440: they are stored in the machine as 32 or 64, this means the same
441: binary file may be read on any machine. Hence you CANNOT use sizeof()
442: to determine the offset or location.
444: Concepts: files^binary seeking
445: Concepts: binary files^seeking
447: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
448: @*/
449: PetscErrorCode PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
450: {
451: int iwhence = 0;
454: if (whence == PETSC_BINARY_SEEK_SET) {
455: iwhence = SEEK_SET;
456: } else if (whence == PETSC_BINARY_SEEK_CUR) {
457: iwhence = SEEK_CUR;
458: } else if (whence == PETSC_BINARY_SEEK_END) {
459: iwhence = SEEK_END;
460: } else {
461: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
462: }
463: #if defined(PETSC_HAVE_LSEEK)
464: *offset = lseek(fd,off,iwhence);
465: #elif defined(PETSC_HAVE__LSEEK)
466: *offset = _lseek(fd,(long)off,iwhence);
467: #else
468: SETERRQ(PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
469: #endif
470: return(0);
471: }
475: /*@C
476: PetscSynchronizedBinaryRead - Reads from a binary file.
478: Collective on MPI_Comm
480: Input Parameters:
481: + comm - the MPI communicator
482: . fd - the file
483: . n - the number of items to read
484: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
486: Output Parameters:
487: . p - the buffer
489: Options Database Key:
490: . -binary_longints - indicates the file was generated on a Cray vector
491: machine (not the T3E/D) and the ints are stored as 64 bit
492: quantities, otherwise they are stored as 32 bit
494: Level: developer
496: Notes:
497: Does a PetscBinaryRead() followed by an MPI_Bcast()
499: PetscSynchronizedBinaryRead() uses byte swapping to work on all machines.
500: Integers are stored on the file as 32 long, regardless of whether
501: they are stored in the machine as 32 or 64, this means the same
502: binary file may be read on any machine.
504: Concepts: files^synchronized reading of binary files
505: Concepts: binary files^reading, synchronized
507: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
508: @*/
509: PetscErrorCode PetscSynchronizedBinaryRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
510: {
512: PetscMPIInt rank;
513: MPI_Datatype mtype;
516: MPI_Comm_rank(comm,&rank);
517: if (!rank) {
518: PetscBinaryRead(fd,p,n,type);
519: }
520: PetscDataTypeToMPIDataType(type,&mtype);
521: MPI_Bcast(p,n,mtype,0,comm);
522: return(0);
523: }
527: /*@C
528: PetscSynchronizedBinaryWrite - writes to a binary file.
530: Collective on MPI_Comm
532: Input Parameters:
533: + comm - the MPI communicator
534: . fd - the file
535: . n - the number of items to write
536: . p - the buffer
537: . istemp - the buffer may be changed
538: - type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
540: Level: developer
542: Notes:
543: Process 0 does a PetscBinaryWrite()
545: PetscSynchronizedBinaryWrite() uses byte swapping to work on all machines.
546: Integers are stored on the file as 32 long, regardless of whether
547: they are stored in the machine as 32 or 64, this means the same
548: binary file may be read on any machine.
550: Concepts: files^synchronized writing of binary files
551: Concepts: binary files^reading, synchronized
553: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
554: @*/
555: PetscErrorCode PetscSynchronizedBinaryWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
556: {
558: PetscMPIInt rank;
561: MPI_Comm_rank(comm,&rank);
562: if (!rank) {
563: PetscBinaryWrite(fd,p,n,type,istemp);
564: }
565: return(0);
566: }
570: /*@C
571: PetscSynchronizedBinarySeek - Moves the file pointer on a PETSc binary file.
574: Input Parameters:
575: + fd - the file
576: . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
577: if PETSC_BINARY_SEEK_CUR then size is offset from current location
578: if PETSC_BINARY_SEEK_END then size is offset from end of file
579: - off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
580: etc. in your calculation rather than sizeof() to compute byte lengths.
582: Output Parameter:
583: . offset - new offset in file
585: Level: developer
587: Notes:
588: Integers are stored on the file as 32 long, regardless of whether
589: they are stored in the machine as 32 or 64, this means the same
590: binary file may be read on any machine. Hence you CANNOT use sizeof()
591: to determine the offset or location.
593: Concepts: binary files^seeking
594: Concepts: files^seeking in binary
596: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
597: @*/
598: PetscErrorCode PetscSynchronizedBinarySeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
599: {
601: PetscMPIInt rank;
604: MPI_Comm_rank(comm,&rank);
605: if (!rank) {
606: PetscBinarySeek(fd,off,whence,offset);
607: }
608: return(0);
609: }