Actual source code: sysio.c
1: /*$Id: sysio.c,v 1.81 2001/08/10 17:39:07 balay Exp $*/
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 (PARCH_win32)
16: #include <io.h>
17: #endif
18: #include petscbt.h
21: #if !defined(PETSC_WORDS_BIGENDIAN)
22: #undef __FUNCT__
24: /*
25: PetscByteSwapInt - Swap bytes in an integer
26: */
27: int PetscByteSwapInt(int *buff,int n)
28: {
29: int i,j,tmp =0;
30: int *tptr = &tmp; /* Need to access tmp indirectly to get */
31: char *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
32:
34: for (j=0; j<n; j++) {
35: ptr1 = (char*)(buff + j);
36: for (i=0; i<(int) sizeof(int); i++) {
37: ptr2[i] = ptr1[sizeof(int)-1-i];
38: }
39: buff[j] = *tptr;
40: }
41: return(0);
42: }
43: /* --------------------------------------------------------- */
44: #undef __FUNCT__
46: /*
47: PetscByteSwapShort - Swap bytes in a short
48: */
49: int PetscByteSwapShort(short *buff,int n)
50: {
51: int i,j;
52: short tmp;
53: short *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
54: char *ptr1,*ptr2 = (char*)&tmp;
57: for (j=0; j<n; j++) {
58: ptr1 = (char*)(buff + j);
59: for (i=0; i<(int) sizeof(short); i++) {
60: ptr2[i] = ptr1[sizeof(int)-1-i];
61: }
62: buff[j] = *tptr;
63: }
64: return(0);
65: }
66: /* --------------------------------------------------------- */
67: #undef __FUNCT__
69: /*
70: PetscByteSwapScalar - Swap bytes in a double
71: Complex is dealt with as if array of double twice as long.
72: */
73: int PetscByteSwapScalar(PetscScalar *buff,int n)
74: {
75: int i,j;
76: PetscReal tmp,*buff1 = (PetscReal*)buff;
77: PetscReal *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
78: char *ptr1,*ptr2 = (char*)&tmp;
81: #if defined(PETSC_USE_COMPLEX)
82: n *= 2;
83: #endif
84: for (j=0; j<n; j++) {
85: ptr1 = (char*)(buff1 + j);
86: for (i=0; i<(int) sizeof(PetscReal); i++) {
87: ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
88: }
89: buff1[j] = *tptr;
90: }
91: return(0);
92: }
93: /* --------------------------------------------------------- */
94: #undef __FUNCT__
96: /*
97: PetscByteSwapDouble - Swap bytes in a double
98: */
99: int PetscByteSwapDouble(double *buff,int n)
100: {
101: int i,j;
102: double tmp,*buff1 = (double*)buff;
103: double *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
104: char *ptr1,*ptr2 = (char*)&tmp;
107: for (j=0; j<n; j++) {
108: ptr1 = (char*)(buff1 + j);
109: for (i=0; i<(int) sizeof(double); i++) {
110: ptr2[i] = ptr1[sizeof(double)-1-i];
111: }
112: buff1[j] = *tptr;
113: }
114: return(0);
115: }
116: #endif
117: /* --------------------------------------------------------- */
118: #undef __FUNCT__
120: /*@C
121: PetscBinaryRead - Reads from a binary file.
123: Not Collective
125: Input Parameters:
126: + fd - the file
127: . n - the number of items to read
128: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
130: Output Parameters:
131: . p - the buffer
133: Options Database Key:
134: . -binary_longints - indicates the file was generated on a Cray vector
135: machine (not the T3E/D) and the ints are stored as 64 bit
136: quantities, otherwise they are stored as 32 bit
138: Level: developer
140: Notes:
141: PetscBinaryRead() uses byte swapping to work on all machines.
142: Integers are stored on the file as 32 long, regardless of whether
143: they are stored in the machine as 32 or 64, this means the same
144: binary file may be read on any machine.
146: Note that Cray C90 and similar machines cannot generate files with
147: 32 bit integers; use the flag -binary_longints to read files from the
148: C90 on non-C90 machines. Cray T3E/T3D are the same as other Unix
149: machines, not the same as the C90.
151: Concepts: files^reading binary
152: Concepts: binary files^reading
154: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose()
155: @*/
156: int PetscBinaryRead(int fd,void *p,int n,PetscDataType type)
157: {
158: int maxblock = 65536,wsize,err,m = n,ierr;
159: static PetscTruth longintset = PETSC_FALSE,longintfile = PETSC_FALSE;
160: PetscTruth flg;
161: char *pp = (char*)p;
162: #if (PETSC_SIZEOF_SHORT != 8)
163: void *ptmp = p;
164: #endif
167: if (!n) return(0);
169: if (!longintset) {
170: PetscOptionsHasName(PETSC_NULL,"-binary_longints",&longintfile);
171: PetscOptionsHasName(PETSC_NULL,"-help",&flg);
172: if (flg) {
173: (*PetscHelpPrintf)(PETSC_COMM_SELF,"-binary_longints - for binary file generatedn
174: on a Cray vector machine (not T3E/T3D)n");
175: }
176: longintset = PETSC_TRUE;
177: }
179: #if (PETSC_SIZEOF_INT == 8 && PETSC_SIZEOF_SHORT == 4)
180: if (type == PETSC_INT){
181: if (longintfile) {
182: m *= sizeof(int);
183: } else {
184: /* read them in as shorts, later stretch into ints */
185: m *= sizeof(short);
186: PetscMalloc(m,&pp);
187: ptmp = (void*)pp;
188: }
189: }
190: #elif (PETSC_SIZEOF_INT == 8 && PETSC_SIZEOF_SHORT == 8)
191: if (type == PETSC_INT){
192: if (longintfile) {
193: m *= sizeof(int);
194: } else {
195: SETERRQ(1,"Can only process data file generated on Cray vector machine;n
196: if this data WAS then run program with -binary_longints option");
197: }
198: }
199: #else
200: if (type == PETSC_INT) {
201: if (longintfile) {
202: /* read in twice as many ints and later discard every other one */
203: m *= 2*sizeof(int);
204: PetscMalloc(m,&pp);
205: ptmp = (void*)pp;
206: } else {
207: m *= sizeof(int);
208: }
209: }
210: #endif
211: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
212: else if (type == PETSC_DOUBLE) m *= sizeof(double);
213: else if (type == PETSC_SHORT) m *= sizeof(short);
214: else if (type == PETSC_CHAR) m *= sizeof(char);
215: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
216: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
217:
218: while (m) {
219: wsize = (m < maxblock) ? m : maxblock;
220: err = read(fd,pp,wsize);
221: if (err < 0 && errno == EINTR) continue;
222: if (err == 0 && wsize > 0) SETERRQ(PETSC_ERR_FILE_READ,"Read past end of file");
223: if (err < 0) SETERRQ(PETSC_ERR_FILE_READ,"Error reading from file");
224: m -= err;
225: pp += err;
226: }
227: #if !defined(PETSC_WORDS_BIGENDIAN)
228: if (type == PETSC_INT) {PetscByteSwapInt((int*)ptmp,n);}
229: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
230: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
231: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
232: #endif
234: #if (PETSC_SIZEOF_INT == 8 && PETSC_SIZEOF_SHORT == 4)
235: if (type == PETSC_INT){
236: if (!longintfile) {
237: int *p_int = (int*)p,i;
238: short *p_short = (short *)ptmp;
239: for (i=0; i<n; i++) {
240: p_int[i] = (int)p_short[i];
241: }
242: PetscFree(ptmp);
243: }
244: }
245: #elif (PETSC_SIZEOF_INT == 8 && PETSC_SIZEOF_SHORT == 8)
246: #else
247: if (type == PETSC_INT){
248: if (longintfile) {
249: /*
250: take the longs (treated as pair of ints) and convert them to ints
251: */
252: int *p_int = (int*)p,i;
253: int *p_intl = (int *)ptmp;
254: for (i=0; i<n; i++) {
255: p_int[i] = (int)p_intl[2*i+1];
256: }
257: PetscFree(ptmp);
258: }
259: }
260: #endif
262: return(0);
263: }
264: /* --------------------------------------------------------- */
265: #undef __FUNCT__
267: /*@C
268: PetscBinaryWrite - Writes to a binary file.
270: Not Collective
272: Input Parameters:
273: + fd - the file
274: . p - the buffer
275: . n - the number of items to write
276: . type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
277: - istemp - 0 if buffer data should be preserved, 1 otherwise.
279: Level: advanced
281: Notes:
282: PetscBinaryWrite() uses byte swapping to work on all machines.
283: Integers are stored on the file as 32 long, regardless of whether
284: they are stored in the machine as 32 or 64, this means the same
285: binary file may be read on any machine.
287: The Buffer p should be read-write buffer, and not static data.
288: This way, byte-swapping is done in-place, and then the buffer is
289: written to the file.
290:
291: This routine restores the original contents of the buffer, after
292: it is written to the file. This is done by byte-swapping in-place
293: the second time. If the flag istemp is set to 1, the second
294: byte-swapping operation is not done, thus saving some computation,
295: but the buffer corrupted is corrupted.
297: Concepts: files^writing binary
298: Concepts: binary files^writing
300: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose()
301: @*/
302: int PetscBinaryWrite(int fd,void *p,int n,PetscDataType type,int istemp)
303: {
304: char *pp = (char*)p;
305: int err,maxblock,wsize,m = n;
306: #if !defined(PETSC_WORDS_BIGENDIAN) || (PETSC_SIZEOF_INT == 8)
307: int ierr;
308: void *ptmp = p;
309: #endif
312: if (!n) return(0);
314: maxblock = 65536;
316: #if !defined(PETSC_WORDS_BIGENDIAN)
317: if (type == PETSC_INT) {PetscByteSwapInt((int*)ptmp,n);}
318: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
319: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
320: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
321: #endif
323: #if (PETSC_SIZEOF_INT == 8)
324: if (type == PETSC_INT){
325: /*
326: integers on the Cray T3d/e are 64 bits so we copy the big
327: integers into a short array and write those out.
328: */
329: int *p_int = (int*)p,i;
330: short *p_short;
331: m *= sizeof(short);
332: ierr = PetscMalloc(m,&pp);
333: ptmp = (void*)pp;
334: p_short = (short*)pp;
336: for (i=0; i<n; i++) {
337: p_short[i] = (short) p_int[i];
338: }
339: }
340: #else
341: if (type == PETSC_INT) m *= sizeof(int);
342: #endif
343: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
344: else if (type == PETSC_DOUBLE) m *= sizeof(double);
345: else if (type == PETSC_SHORT) m *= sizeof(short);
346: else if (type == PETSC_CHAR) m *= sizeof(char);
347: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
348: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
350: while (m) {
351: wsize = (m < maxblock) ? m : maxblock;
352: err = write(fd,pp,wsize);
353: if (err < 0 && errno == EINTR) continue;
354: if (err != wsize) SETERRQ(PETSC_ERR_FILE_WRITE,"Error writing to file.");
355: m -= wsize;
356: pp += wsize;
357: }
359: #if !defined(PETSC_WORDS_BIGENDIAN)
360: if (!istemp) {
361: if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
362: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
363: else if (type == PETSC_INT) {PetscByteSwapInt((int*)ptmp,n);}
364: }
365: #endif
367: #if (PETSC_SIZEOF_INT == 8)
368: if (type == PETSC_INT){
369: PetscFree(ptmp);
370: }
371: #endif
373: return(0);
374: }
376: #undef __FUNCT__
378: /*@C
379: PetscBinaryOpen - Opens a PETSc binary file.
381: Not Collective
383: Input Parameters:
384: + name - filename
385: - type - type of binary file, on of PETSC_BINARY_RDONLY, PETSC_BINARY_WRONLY, PETSC_BINARY_CREATE
387: Output Parameter:
388: . fd - the file
390: Level: advanced
392: Concepts: files^opening binary
393: Concepts: binary files^opening
395: .seealso: PetscBinaryRead(), PetscBinaryWrite()
396: @*/
397: int PetscBinaryOpen(const char name[],int type,int *fd)
398: {
400: #if defined(PARCH_win32_gnu) || defined(PARCH_win32)
401: if (type == PETSC_BINARY_CREATE) {
402: if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
403: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
404: }
405: } else if (type == PETSC_BINARY_RDONLY) {
406: if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
407: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
408: }
409: } else if (type == PETSC_BINARY_WRONLY) {
410: if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
411: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
412: }
413: #else
414: if (type == PETSC_BINARY_CREATE) {
415: if ((*fd = creat(name,0666)) == -1) {
416: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
417: }
418: } else if (type == PETSC_BINARY_RDONLY) {
419: if ((*fd = open(name,O_RDONLY,0)) == -1) {
420: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
421: }
422: }
423: else if (type == PETSC_BINARY_WRONLY) {
424: if ((*fd = open(name,O_WRONLY,0)) == -1) {
425: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
426: }
427: #endif
428: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file type");
429: return(0);
430: }
432: #undef __FUNCT__
434: /*@C
435: PetscBinaryClose - Closes a PETSc binary file.
437: Not Collective
439: Output Parameter:
440: . fd - the file
442: Level: advanced
444: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
445: @*/
446: int PetscBinaryClose(int fd)
447: {
449: close(fd);
450: return(0);
451: }
454: #undef __FUNCT__
456: /*@C
457: PetscBinarySeek - Moves the file pointer on a PETSc binary file.
459: Not Collective
461: Input Parameters:
462: + fd - the file
463: . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
464: if PETSC_BINARY_SEEK_CUR then size is offset from current location
465: if PETSC_BINARY_SEEK_END then size is offset from end of file
466: - size - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
467: etc. in your calculation rather than sizeof() to compute byte lengths.
469: Output Parameter:
470: . offset - new offset in file
472: Level: developer
474: Notes:
475: Integers are stored on the file as 32 long, regardless of whether
476: they are stored in the machine as 32 or 64, this means the same
477: binary file may be read on any machine. Hence you CANNOT use sizeof()
478: to determine the offset or location.
480: Concepts: files^binary seeking
481: Concepts: binary files^seeking
483: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
484: @*/
485: int PetscBinarySeek(int fd,int size,PetscBinarySeekType whence,int *offset)
486: {
487: int iwhence=0;
490: if (whence == PETSC_BINARY_SEEK_SET) {
491: iwhence = SEEK_SET;
492: } else if (whence == PETSC_BINARY_SEEK_CUR) {
493: iwhence = SEEK_CUR;
494: } else if (whence == PETSC_BINARY_SEEK_END) {
495: iwhence = SEEK_END;
496: } else {
497: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
498: }
499: #if defined(PARCH_win32)
500: *offset = _lseek(fd,(long)size,iwhence);
501: #else
502: *offset = lseek(fd,(off_t)size,iwhence);
503: #endif
505: return(0);
506: }
508: #undef __FUNCT__
510: /*@C
511: PetscSynchronizedBinaryRead - Reads from a binary file.
513: Collective on MPI_Comm
515: Input Parameters:
516: + comm - the MPI communicator
517: . fd - the file
518: . n - the number of items to read
519: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
521: Output Parameters:
522: . p - the buffer
524: Options Database Key:
525: . -binary_longints - indicates the file was generated on a Cray vector
526: machine (not the T3E/D) and the ints are stored as 64 bit
527: quantities, otherwise they are stored as 32 bit
529: Level: developer
531: Notes:
532: Does a PetscBinaryRead() followed by an MPI_Bcast()
534: PetscSynchronizedBinaryRead() uses byte swapping to work on all machines.
535: Integers are stored on the file as 32 long, regardless of whether
536: they are stored in the machine as 32 or 64, this means the same
537: binary file may be read on any machine.
539: Note that Cray C90 and similar machines cannot generate files with
540: 32 bit integers; use the flag -binary_longints to read files from the
541: C90 on non-C90 machines. Cray T3E/T3D are the same as other Unix
542: machines, not the same as the C90.
544: Concepts: files^synchronized reading of binary files
545: Concepts: binary files^reading, synchronized
547: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
548: @*/
549: int PetscSynchronizedBinaryRead(MPI_Comm comm,int fd,void *p,int n,PetscDataType type)
550: {
551: int ierr,rank;
552: MPI_Datatype mtype;
555: MPI_Comm_rank(comm,&rank);
556: if (!rank) {
557: PetscBinaryRead(fd,p,n,type);
558: }
559: PetscDataTypeToMPIDataType(type,&mtype);
560: MPI_Bcast(p,n,mtype,0,comm);
561: return(0);
562: }
564: #undef __FUNCT__
566: /*@C
567: PetscSynchronizedBinarySeek - Moves the file pointer on a PETSc binary file.
569: Not Collective
571: Input Parameters:
572: + fd - the file
573: . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
574: if PETSC_BINARY_SEEK_CUR then size is offset from current location
575: if PETSC_BINARY_SEEK_END then size is offset from end of file
576: - size - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
577: etc. in your calculation rather than sizeof() to compute byte lengths.
579: Output Parameter:
580: . offset - new offset in file
582: Level: developer
584: Notes:
585: Integers are stored on the file as 32 long, regardless of whether
586: they are stored in the machine as 32 or 64, this means the same
587: binary file may be read on any machine. Hence you CANNOT use sizeof()
588: to determine the offset or location.
590: Concepts: binary files^seeking
591: Concepts: files^seeking in binary
593: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
594: @*/
595: int PetscSynchronizedBinarySeek(MPI_Comm comm,int fd,int size,PetscBinarySeekType whence,int *offset)
596: {
597: int ierr,rank;
600: MPI_Comm_rank(comm,&rank);
601: if (!rank) {
602: PetscBinarySeek(fd,size,whence,offset);
603: }
604: return(0);
605: }