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) SETERRQ1(PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
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)
318: if (!istemp) {
319: if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
320: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
321: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
322: else if (type == PETSC_INT) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
323: else if (type == PETSC_ENUM) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
324: else if (type == PETSC_TRUTH) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
325: }
326: #endif
328: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
329: if (type == PETSC_INT){
330: PetscFree(ptmp);
331: }
332: #endif
333: return(0);
334: }
338: /*@C
339: PetscBinaryOpen - Opens a PETSc binary file.
341: Not Collective
343: Input Parameters:
344: + name - filename
345: - type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE
347: Output Parameter:
348: . fd - the file
350: Level: advanced
352: Concepts: files^opening binary
353: Concepts: binary files^opening
355: Notes: Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
356: big-endian format. This means the file can be accessed using PetscBinaryOpen() and
357: PetscBinaryRead() and PetscBinaryWrite() on any machine.
359: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor()
361: @*/
362: PetscErrorCode PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
363: {
365: #if defined(PETSC_HAVE_O_BINARY)
366: if (mode == FILE_MODE_WRITE) {
367: if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
368: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
369: }
370: } else if (mode == FILE_MODE_READ) {
371: if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
372: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
373: }
374: } else if (mode == FILE_MODE_APPEND) {
375: if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
376: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
377: }
378: #else
379: if (mode == FILE_MODE_WRITE) {
380: if ((*fd = creat(name,0666)) == -1) {
381: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
382: }
383: } else if (mode == FILE_MODE_READ) {
384: if ((*fd = open(name,O_RDONLY,0)) == -1) {
385: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
386: }
387: }
388: else if (mode == FILE_MODE_APPEND) {
389: if ((*fd = open(name,O_WRONLY,0)) == -1) {
390: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
391: }
392: #endif
393: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
394: return(0);
395: }
399: /*@
400: PetscBinaryClose - Closes a PETSc binary file.
402: Not Collective
404: Output Parameter:
405: . fd - the file
407: Level: advanced
409: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
410: @*/
411: PetscErrorCode PetscBinaryClose(int fd)
412: {
414: close(fd);
415: return(0);
416: }
421: /*@
422: PetscBinarySeek - Moves the file pointer on a PETSc binary file.
424: Not Collective
426: Input Parameters:
427: + fd - the file
428: . off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
429: etc. in your calculation rather than sizeof() to compute byte lengths.
430: - whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
431: if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
432: if PETSC_BINARY_SEEK_END then off is an offset from the end of file
434: Output Parameter:
435: . offset - new offset in file
437: Level: developer
439: Notes:
440: Integers are stored on the file as 32 long, regardless of whether
441: they are stored in the machine as 32 or 64, this means the same
442: binary file may be read on any machine. Hence you CANNOT use sizeof()
443: to determine the offset or location.
445: Concepts: files^binary seeking
446: Concepts: binary files^seeking
448: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
449: @*/
450: PetscErrorCode PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
451: {
452: int iwhence = 0;
455: if (whence == PETSC_BINARY_SEEK_SET) {
456: iwhence = SEEK_SET;
457: } else if (whence == PETSC_BINARY_SEEK_CUR) {
458: iwhence = SEEK_CUR;
459: } else if (whence == PETSC_BINARY_SEEK_END) {
460: iwhence = SEEK_END;
461: } else {
462: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
463: }
464: #if defined(PETSC_HAVE_LSEEK)
465: *offset = lseek(fd,off,iwhence);
466: #elif defined(PETSC_HAVE__LSEEK)
467: *offset = _lseek(fd,(long)off,iwhence);
468: #else
469: SETERRQ(PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
470: #endif
471: return(0);
472: }
476: /*@C
477: PetscBinarySynchronizedRead - Reads from a binary file.
479: Collective on MPI_Comm
481: Input Parameters:
482: + comm - the MPI communicator
483: . fd - the file
484: . n - the number of items to read
485: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
487: Output Parameters:
488: . p - the buffer
490: Options Database Key:
491: . -binary_longints - indicates the file was generated on a Cray vector
492: machine (not the T3E/D) and the ints are stored as 64 bit
493: quantities, otherwise they are stored as 32 bit
495: Level: developer
497: Notes:
498: Does a PetscBinaryRead() followed by an MPI_Bcast()
500: PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
501: Integers are stored on the file as 32 long, regardless of whether
502: they are stored in the machine as 32 or 64, this means the same
503: binary file may be read on any machine.
505: Concepts: files^synchronized reading of binary files
506: Concepts: binary files^reading, synchronized
508: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
509: @*/
510: PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
511: {
513: PetscMPIInt rank;
514: MPI_Datatype mtype;
517: MPI_Comm_rank(comm,&rank);
518: if (!rank) {
519: PetscBinaryRead(fd,p,n,type);
520: }
521: PetscDataTypeToMPIDataType(type,&mtype);
522: MPI_Bcast(p,n,mtype,0,comm);
523: return(0);
524: }
528: /*@C
529: PetscBinarySynchronizedWrite - writes to a binary file.
531: Collective on MPI_Comm
533: Input Parameters:
534: + comm - the MPI communicator
535: . fd - the file
536: . n - the number of items to write
537: . p - the buffer
538: . istemp - the buffer may be changed
539: - type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
541: Level: developer
543: Notes:
544: Process 0 does a PetscBinaryWrite()
546: PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
547: Integers are stored on the file as 32 long, regardless of whether
548: they are stored in the machine as 32 or 64, this means the same
549: binary file may be read on any machine.
551: WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
552: while PetscSynchronizedFPrintf() has all processes print their strings in order.
554: Concepts: files^synchronized writing of binary files
555: Concepts: binary files^reading, synchronized
557: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
558: @*/
559: PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
560: {
562: PetscMPIInt rank;
565: MPI_Comm_rank(comm,&rank);
566: if (!rank) {
567: PetscBinaryWrite(fd,p,n,type,istemp);
568: }
569: return(0);
570: }
574: /*@C
575: PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
578: Input Parameters:
579: + fd - the file
580: . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
581: if PETSC_BINARY_SEEK_CUR then size is offset from current location
582: if PETSC_BINARY_SEEK_END then size is offset from end of file
583: - off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
584: etc. in your calculation rather than sizeof() to compute byte lengths.
586: Output Parameter:
587: . offset - new offset in file
589: Level: developer
591: Notes:
592: Integers are stored on the file as 32 long, regardless of whether
593: they are stored in the machine as 32 or 64, this means the same
594: binary file may be read on any machine. Hence you CANNOT use sizeof()
595: to determine the offset or location.
597: Concepts: binary files^seeking
598: Concepts: files^seeking in binary
600: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
601: @*/
602: PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
603: {
605: PetscMPIInt rank;
608: MPI_Comm_rank(comm,&rank);
609: if (!rank) {
610: PetscBinarySeek(fd,off,whence,offset);
611: }
612: return(0);
613: }