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(), PetscBinarySynchronizedWrite(),
157: PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
158: @*/
159: PetscErrorCode PetscBinaryRead(int fd,void *p,PetscInt n,PetscDataType type)
160: {
161: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES) || !defined(PETSC_WORDS_BIGENDIAN)
162: PetscErrorCode ierr;
163: #endif
164: int wsize,err;
165: size_t m = (size_t) n,maxblock = 65536;
166: char *pp = (char*)p;
167: #if (PETSC_SIZEOF_INT == 8) || !defined(PETSC_WORDS_BIGENDIAN) || defined(PETSC_USE_64BIT_INDICES)
168: void *ptmp = p;
169: #endif
172: if (!n) return(0);
174: if (type == PETSC_INT){
175: m *= sizeof(PetscInt32);
176: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
177: /* read them in as 32 bit ints, later stretch into ints */
178: PetscMalloc(m,&pp);
179: ptmp = (void*)pp;
180: #endif
181: }
182: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
183: else if (type == PETSC_DOUBLE) m *= sizeof(double);
184: else if (type == PETSC_SHORT) m *= sizeof(short);
185: else if (type == PETSC_CHAR) m *= sizeof(char);
186: else if (type == PETSC_ENUM) m *= sizeof(PetscEnum);
187: else if (type == PETSC_TRUTH) m *= sizeof(PetscTruth);
188: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
189: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
190:
191: while (m) {
192: wsize = (m < maxblock) ? m : maxblock;
193: err = read(fd,pp,wsize);
194: if (err < 0 && errno == EINTR) continue;
195: if (!err && wsize > 0) SETERRQ(PETSC_ERR_FILE_READ,"Read past end of file");
196: if (err < 0) SETERRQ1(PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
197: m -= err;
198: pp += err;
199: }
200: #if !defined(PETSC_WORDS_BIGENDIAN)
201: if (type == PETSC_INT) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
202: else if (type == PETSC_ENUM) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
203: else if (type == PETSC_TRUTH) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
204: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
205: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
206: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
207: #endif
209: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
210: if (type == PETSC_INT) {
211: PetscInt *p_int = (PetscInt*)p,i;
212: PetscInt32 *p_short = (PetscInt32 *)ptmp;
213: for (i=0; i<n; i++) {
214: p_int[i] = (PetscInt)p_short[i];
215: }
216: PetscFree(ptmp);
217: }
218: #endif
219: return(0);
220: }
221: /* --------------------------------------------------------- */
224: /*@
225: PetscBinaryWrite - Writes to a binary file.
227: Not Collective
229: Input Parameters:
230: + fd - the file
231: . p - the buffer
232: . n - the number of items to write
233: . type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
234: - istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.
236: Level: advanced
238: Notes:
239: PetscBinaryWrite() uses byte swapping to work on all machines; the files
240: are written using big-endian ordering to the file. On small-endian machines the numbers
241: are converted to the big-endian format when they are written to disk.
242: Integers are stored on the file as 32 bits long, regardless of whether
243: they are stored in the machine as 32 bits or 64 bits, this means the same
244: binary file may be read on any machine. It also means that 64 bit integers larger than
245: roughly 2 billion are TRUNCATED/WRONG when written to the file.
247: The Buffer p should be read-write buffer, and not static data.
248: This way, byte-swapping is done in-place, and then the buffer is
249: written to the file.
250:
251: This routine restores the original contents of the buffer, after
252: it is written to the file. This is done by byte-swapping in-place
253: the second time. If the flag istemp is set to PETSC_TRUE, the second
254: byte-swapping operation is not done, thus saving some computation,
255: but the buffer corrupted is corrupted.
257: Concepts: files^writing binary
258: Concepts: binary files^writing
260: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
261: PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
262: @*/
263: PetscErrorCode PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
264: {
265: char *pp = (char*)p;
266: int err,wsize;
267: size_t m = (size_t)n,maxblock=65536;
268: #if !defined(PETSC_WORDS_BIGENDIAN) || (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
270: void *ptmp = p;
271: #endif
274: if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
275: if (!n) return(0);
277: if (type == PETSC_INT){
278: m *= sizeof(PetscInt32);
279: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
280: PetscInt *p_int = (PetscInt*)p,i;
281: PetscInt32 *p_short;
282: PetscMalloc(m,&pp);
283: ptmp = (void*)pp;
284: p_short = (PetscInt32*)pp;
286: for (i=0; i<n; i++) {
287: p_short[i] = (PetscInt32) p_int[i];
288: }
289: istemp = PETSC_TRUE;
290: #endif
291: }
292: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
293: else if (type == PETSC_DOUBLE) m *= sizeof(double);
294: else if (type == PETSC_SHORT) m *= sizeof(short);
295: else if (type == PETSC_CHAR) m *= sizeof(char);
296: else if (type == PETSC_ENUM) m *= sizeof(PetscEnum);
297: else if (type == PETSC_TRUTH) m *= sizeof(PetscTruth);
298: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
299: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
301: #if !defined(PETSC_WORDS_BIGENDIAN)
302: if (type == PETSC_INT) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
303: else if (type == PETSC_ENUM) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
304: else if (type == PETSC_TRUTH) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
305: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
306: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
307: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
308: #endif
310: while (m) {
311: wsize = (m < maxblock) ? m : maxblock;
312: err = write(fd,pp,wsize);
313: if (err < 0 && errno == EINTR) continue;
314: if (err != wsize) SETERRQ(PETSC_ERR_FILE_WRITE,"Error writing to file.");
315: m -= wsize;
316: pp += wsize;
317: }
319: #if !defined(PETSC_WORDS_BIGENDIAN)
320: if (!istemp) {
321: if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
322: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
323: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
324: else if (type == PETSC_INT) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
325: else if (type == PETSC_ENUM) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
326: else if (type == PETSC_TRUTH) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
327: }
328: #endif
330: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
331: if (type == PETSC_INT){
332: PetscFree(ptmp);
333: }
334: #endif
335: return(0);
336: }
340: /*@C
341: PetscBinaryOpen - Opens a PETSc binary file.
343: Not Collective
345: Input Parameters:
346: + name - filename
347: - type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE
349: Output Parameter:
350: . fd - the file
352: Level: advanced
354: Concepts: files^opening binary
355: Concepts: binary files^opening
357: Notes: Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
358: big-endian format. This means the file can be accessed using PetscBinaryOpen() and
359: PetscBinaryRead() and PetscBinaryWrite() on any machine.
361: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
362: PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
364: @*/
365: PetscErrorCode PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
366: {
368: #if defined(PETSC_HAVE_O_BINARY)
369: if (mode == FILE_MODE_WRITE) {
370: if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
371: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
372: }
373: } else if (mode == FILE_MODE_READ) {
374: if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
375: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
376: }
377: } else if (mode == FILE_MODE_APPEND) {
378: if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
379: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
380: }
381: #else
382: if (mode == FILE_MODE_WRITE) {
383: if ((*fd = creat(name,0666)) == -1) {
384: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
385: }
386: } else if (mode == FILE_MODE_READ) {
387: if ((*fd = open(name,O_RDONLY,0)) == -1) {
388: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
389: }
390: }
391: else if (mode == FILE_MODE_APPEND) {
392: if ((*fd = open(name,O_WRONLY,0)) == -1) {
393: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
394: }
395: #endif
396: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
397: return(0);
398: }
402: /*@
403: PetscBinaryClose - Closes a PETSc binary file.
405: Not Collective
407: Output Parameter:
408: . fd - the file
410: Level: advanced
412: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
413: PetscBinarySynchronizedSeek()
414: @*/
415: PetscErrorCode PetscBinaryClose(int fd)
416: {
418: close(fd);
419: return(0);
420: }
425: /*@
426: PetscBinarySeek - Moves the file pointer on a PETSc binary file.
428: Not Collective
430: Input Parameters:
431: + fd - the file
432: . off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
433: etc. in your calculation rather than sizeof() to compute byte lengths.
434: - whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
435: if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
436: if PETSC_BINARY_SEEK_END then off is an offset from the end of file
438: Output Parameter:
439: . offset - new offset in file
441: Level: developer
443: Notes:
444: Integers are stored on the file as 32 long, regardless of whether
445: they are stored in the machine as 32 or 64, this means the same
446: binary file may be read on any machine. Hence you CANNOT use sizeof()
447: to determine the offset or location.
449: Concepts: files^binary seeking
450: Concepts: binary files^seeking
452: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
453: PetscBinarySynchronizedSeek()
454: @*/
455: PetscErrorCode PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
456: {
457: int iwhence = 0;
460: if (whence == PETSC_BINARY_SEEK_SET) {
461: iwhence = SEEK_SET;
462: } else if (whence == PETSC_BINARY_SEEK_CUR) {
463: iwhence = SEEK_CUR;
464: } else if (whence == PETSC_BINARY_SEEK_END) {
465: iwhence = SEEK_END;
466: } else {
467: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
468: }
469: #if defined(PETSC_HAVE_LSEEK)
470: *offset = lseek(fd,off,iwhence);
471: #elif defined(PETSC_HAVE__LSEEK)
472: *offset = _lseek(fd,(long)off,iwhence);
473: #else
474: SETERRQ(PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
475: #endif
476: return(0);
477: }
481: /*@C
482: PetscBinarySynchronizedRead - Reads from a binary file.
484: Collective on MPI_Comm
486: Input Parameters:
487: + comm - the MPI communicator
488: . fd - the file
489: . n - the number of items to read
490: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
492: Output Parameters:
493: . p - the buffer
495: Options Database Key:
496: . -binary_longints - indicates the file was generated on a Cray vector
497: machine (not the T3E/D) and the ints are stored as 64 bit
498: quantities, otherwise they are stored as 32 bit
500: Level: developer
502: Notes:
503: Does a PetscBinaryRead() followed by an MPI_Bcast()
505: PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
506: Integers are stored on the file as 32 long, regardless of whether
507: they are stored in the machine as 32 or 64, this means the same
508: binary file may be read on any machine.
510: Concepts: files^synchronized reading of binary files
511: Concepts: binary files^reading, synchronized
513: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
514: PetscBinarySynchronizedSeek()
515: @*/
516: PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
517: {
519: PetscMPIInt rank;
520: MPI_Datatype mtype;
523: MPI_Comm_rank(comm,&rank);
524: if (!rank) {
525: PetscBinaryRead(fd,p,n,type);
526: }
527: PetscDataTypeToMPIDataType(type,&mtype);
528: MPI_Bcast(p,n,mtype,0,comm);
529: return(0);
530: }
534: /*@C
535: PetscBinarySynchronizedWrite - writes to a binary file.
537: Collective on MPI_Comm
539: Input Parameters:
540: + comm - the MPI communicator
541: . fd - the file
542: . n - the number of items to write
543: . p - the buffer
544: . istemp - the buffer may be changed
545: - type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
547: Level: developer
549: Notes:
550: Process 0 does a PetscBinaryWrite()
552: PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
553: Integers are stored on the file as 32 long, regardless of whether
554: they are stored in the machine as 32 or 64, this means the same
555: binary file may be read on any machine.
557: WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
558: while PetscSynchronizedFPrintf() has all processes print their strings in order.
560: Concepts: files^synchronized writing of binary files
561: Concepts: binary files^reading, synchronized
563: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
564: PetscBinarySynchronizedSeek()
565: @*/
566: PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
567: {
569: PetscMPIInt rank;
572: MPI_Comm_rank(comm,&rank);
573: if (!rank) {
574: PetscBinaryWrite(fd,p,n,type,istemp);
575: }
576: return(0);
577: }
581: /*@C
582: PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
585: Input Parameters:
586: + fd - the file
587: . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
588: if PETSC_BINARY_SEEK_CUR then size is offset from current location
589: if PETSC_BINARY_SEEK_END then size is offset from end of file
590: - off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
591: etc. in your calculation rather than sizeof() to compute byte lengths.
593: Output Parameter:
594: . offset - new offset in file
596: Level: developer
598: Notes:
599: Integers are stored on the file as 32 long, regardless of whether
600: they are stored in the machine as 32 or 64, this means the same
601: binary file may be read on any machine. Hence you CANNOT use sizeof()
602: to determine the offset or location.
604: Concepts: binary files^seeking
605: Concepts: files^seeking in binary
607: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
608: PetscBinarySynchronizedSeek()
609: @*/
610: PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
611: {
613: PetscMPIInt rank;
616: MPI_Comm_rank(comm,&rank);
617: if (!rank) {
618: PetscBinarySeek(fd,off,whence,offset);
619: }
620: return(0);
621: }