xref: /petsc/src/sys/fileio/sysio.c (revision d6685f554fbda8d96c6a5d73ab0e7a4e21a05c51)
1 
2 /*
3    This file contains simple binary read/write routines.
4  */
5 
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
19 
20 const char *const PetscFileModes[] = {"READ","WRITE","APPEND","UPDATE","APPEND_UPDATE","PetscFileMode","PETSC_FILE_",NULL};
21 
22 /* --------------------------------------------------------- */
23 /*
24   PetscByteSwapEnum - Swap bytes in a  PETSc Enum
25 
26 */
27 PetscErrorCode  PetscByteSwapEnum(PetscEnum *buff,PetscInt n)
28 {
29   PetscInt  i,j;
30   PetscEnum tmp = ENUM_DUMMY;
31   char      *ptr1,*ptr2 = (char*)&tmp;
32 
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(0);
40 }
41 
42 /*
43   PetscByteSwapBool - Swap bytes in a  PETSc Bool
44 
45 */
46 PetscErrorCode  PetscByteSwapBool(PetscBool *buff,PetscInt n)
47 {
48   PetscInt  i,j;
49   PetscBool tmp = PETSC_FALSE;
50   char      *ptr1,*ptr2 = (char*)&tmp;
51 
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(0);
59 }
60 
61 /*
62   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64 bits)
63 
64 */
65 PetscErrorCode  PetscByteSwapInt(PetscInt *buff,PetscInt n)
66 {
67   PetscInt i,j,tmp = 0;
68   char     *ptr1,*ptr2 = (char*)&tmp;
69 
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(0);
77 }
78 
79 /*
80   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64 bits)
81 
82 */
83 PetscErrorCode  PetscByteSwapInt64(PetscInt64 *buff,PetscInt n)
84 {
85   PetscInt   i,j;
86   PetscInt64 tmp = 0;
87   char       *ptr1,*ptr2 = (char*)&tmp;
88 
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(0);
96 }
97 
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;
107 
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(0);
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;
124 
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(0);
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;
142 
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(0);
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;
161 
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(0);
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;
182 
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(0);
190 }
191 
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;
200 
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(0);
208 }
209 
210 PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count)
211 {
212   PetscErrorCode ierr;
213 
214   PetscFunctionBegin;
215   if      (pdtype == PETSC_INT)    {ierr = PetscByteSwapInt((PetscInt*)data,count);CHKERRQ(ierr);}
216   else if (pdtype == PETSC_ENUM)   {ierr = PetscByteSwapEnum((PetscEnum*)data,count);CHKERRQ(ierr);}
217   else if (pdtype == PETSC_BOOL)   {ierr = PetscByteSwapBool((PetscBool*)data,count);CHKERRQ(ierr);}
218   else if (pdtype == PETSC_SCALAR) {ierr = PetscByteSwapScalar((PetscScalar*)data,count);CHKERRQ(ierr);}
219   else if (pdtype == PETSC_REAL)   {ierr = PetscByteSwapReal((PetscReal*)data,count);CHKERRQ(ierr);}
220   else if (pdtype == PETSC_COMPLEX){ierr = PetscByteSwapReal((PetscReal*)data,2*count);CHKERRQ(ierr);}
221   else if (pdtype == PETSC_INT64)  {ierr = PetscByteSwapInt64((PetscInt64*)data,count);CHKERRQ(ierr);}
222   else if (pdtype == PETSC_DOUBLE) {ierr = PetscByteSwapDouble((double*)data,count);CHKERRQ(ierr);}
223   else if (pdtype == PETSC_FLOAT)  {ierr = PetscByteSwapFloat((float*)data,count);CHKERRQ(ierr);}
224   else if (pdtype == PETSC_SHORT)  {ierr = PetscByteSwapShort((short*)data,count);CHKERRQ(ierr);}
225   else if (pdtype == PETSC_LONG)   {ierr = PetscByteSwapLong((long*)data,count);CHKERRQ(ierr);}
226   PetscFunctionReturn(0);
227 }
228 
229 /*@C
230    PetscBinaryRead - Reads from a binary file.
231 
232    Not Collective
233 
234    Input Parameters:
235 +  fd - the file descriptor
236 .  num  - the maximum number of items to read
237 -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)
238 
239    Output Parameters:
240 +  data - the buffer
241 -  count - the number of items read, optional
242 
243    Level: developer
244 
245    Notes:
246    If count is not provided and the number of items read is less than
247    the maximum number of items to read, then this routine errors.
248 
249    PetscBinaryRead() uses byte swapping to work on all machines; the files
250    are written to file ALWAYS using big-endian ordering. On little-endian machines the numbers
251    are converted to the little-endian format when they are read in from the file.
252    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
253    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
254    is used.
255 
256 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
257           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
258 @*/
259 PetscErrorCode  PetscBinaryRead(int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
260 {
261   size_t            typesize, m = (size_t) num, n = 0, maxblock = 65536;
262   char              *p = (char*)data;
263 #if defined(PETSC_USE_REAL___FLOAT128)
264   PetscBool         readdouble = PETSC_FALSE;
265   double            *pdouble;
266 #endif
267   void              *ptmp = data;
268   char              *fname = NULL;
269   PetscErrorCode    ierr;
270 
271   PetscFunctionBegin;
272   if (count) *count = 0;
273   PetscCheckFalse(num < 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to read a negative amount of data %" PetscInt_FMT,num);
274   if (!num) PetscFunctionReturn(0);
275 
276   if (type == PETSC_FUNCTION) {
277     m     = 64;
278     type  = PETSC_CHAR;
279     fname = (char*)malloc(m*sizeof(char));
280     p     = (char*)fname;
281     ptmp  = (void*)fname;
282     PetscCheckFalse(!fname,PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
283   }
284   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m);
285 
286   ierr = PetscDataTypeGetSize(type,&typesize);CHKERRQ(ierr);
287 
288 #if defined(PETSC_USE_REAL___FLOAT128)
289   ierr = PetscOptionsGetBool(NULL,NULL,"-binary_read_double",&readdouble,NULL);CHKERRQ(ierr);
290   /* If using __float128 precision we still read in doubles from file */
291   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
292     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
293     ierr = PetscMalloc1(cnt,&pdouble);CHKERRQ(ierr);
294     p = (char*)pdouble;
295     typesize /= 2;
296   }
297 #endif
298 
299   m *= typesize;
300 
301   while (m) {
302     size_t len = (m < maxblock) ? m : maxblock;
303     int    ret = (int)read(fd,p,len);
304     if (ret < 0 && errno == EINTR) continue;
305     if (!ret && len > 0) break; /* Proxy for EOF */
306     PetscCheckFalse(ret < 0,PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
307     m -= (size_t)ret;
308     p += ret;
309     n += (size_t)ret;
310   }
311   PetscCheckFalse(m && !count,PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Read past end of file");
312 
313   num = (PetscInt)(n/typesize); /* Should we require `n % typesize == 0` ? */
314   if (count) *count = num;      /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */
315 
316 #if defined(PETSC_USE_REAL___FLOAT128)
317   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
318     PetscInt  i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
319     PetscReal *preal = (PetscReal*)data;
320     if (!PetscBinaryBigEndian()) {ierr = PetscByteSwapDouble(pdouble,cnt);CHKERRQ(ierr);}
321     for (i=0; i<cnt; i++) preal[i] = pdouble[i];
322     ierr = PetscFree(pdouble);CHKERRQ(ierr);
323     PetscFunctionReturn(0);
324   }
325 #endif
326 
327   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(ptmp,type,num);CHKERRQ(ierr);}
328 
329   if (type == PETSC_FUNCTION) {
330 #if defined(PETSC_SERIALIZE_FUNCTIONS)
331     ierr = PetscDLSym(NULL,fname,(void**)data);CHKERRQ(ierr);
332 #else
333     *(void**)data = NULL;
334 #endif
335     free(fname);
336   }
337   PetscFunctionReturn(0);
338 }
339 
340 /*@C
341    PetscBinaryWrite - Writes to a binary file.
342 
343    Not Collective
344 
345    Input Parameters:
346 +  fd     - the file
347 .  p      - the buffer
348 .  n      - the number of items to write
349 -  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
350 
351    Level: advanced
352 
353    Notes:
354    PetscBinaryWrite() uses byte swapping to work on all machines; the files
355    are written using big-endian ordering to the file. On little-endian machines the numbers
356    are converted to the big-endian format when they are written to disk.
357    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
358    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
359    is used.
360 
361    If running with __float128 precision the output is in __float128 unless one uses the -binary_write_double option
362 
363    The Buffer p should be read-write buffer, and not static data.
364    This way, byte-swapping is done in-place, and then the buffer is
365    written to the file.
366 
367    This routine restores the original contents of the buffer, after
368    it is written to the file. This is done by byte-swapping in-place
369    the second time.
370 
371    Because byte-swapping may be done on the values in data it cannot be declared const
372 
373 .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
374           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
375 @*/
376 PetscErrorCode  PetscBinaryWrite(int fd,const void *p,PetscInt n,PetscDataType type)
377 {
378   const char     *pp = (char*)p;
379   int            err,wsize;
380   size_t         m = (size_t)n,maxblock=65536;
381   PetscErrorCode ierr;
382   const void     *ptmp = p;
383   char           *fname = NULL;
384 #if defined(PETSC_USE_REAL___FLOAT128)
385   PetscBool      writedouble = PETSC_FALSE;
386   double         *ppp;
387   PetscReal      *pv;
388   PetscInt       i;
389 #endif
390   PetscDataType  wtype = type;
391 
392   PetscFunctionBegin;
393   PetscCheckFalse(n < 0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %" PetscInt_FMT,n);
394   if (!n) PetscFunctionReturn(0);
395 
396   if (type == PETSC_FUNCTION) {
397 #if defined(PETSC_SERIALIZE_FUNCTIONS)
398     const char *fnametmp;
399 #endif
400     m     = 64;
401     fname = (char*)malloc(m*sizeof(char));
402     PetscCheckFalse(!fname,PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
403 #if defined(PETSC_SERIALIZE_FUNCTIONS)
404     PetscCheckFalse(n > 1,PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
405     ierr = PetscFPTFind(*(void**)p,&fnametmp);CHKERRQ(ierr);
406     ierr = PetscStrncpy(fname,fnametmp,m);CHKERRQ(ierr);
407 #else
408     ierr = PetscStrncpy(fname,"",m);CHKERRQ(ierr);
409 #endif
410     wtype = PETSC_CHAR;
411     pp    = (char*)fname;
412     ptmp  = (void*)fname;
413   }
414 
415 #if defined(PETSC_USE_REAL___FLOAT128)
416   ierr = PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);CHKERRQ(ierr);
417   /* If using __float128 precision we still write in doubles to file */
418   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
419     wtype = PETSC_DOUBLE;
420     ierr = PetscMalloc1(n,&ppp);CHKERRQ(ierr);
421     pv = (PetscReal*)pp;
422     for (i=0; i<n; i++) {
423       ppp[i] = (double) pv[i];
424     }
425     pp   = (char*)ppp;
426     ptmp = (char*)ppp;
427   }
428 #endif
429 
430   if (wtype == PETSC_INT)          m *= sizeof(PetscInt);
431   else if (wtype == PETSC_SCALAR)  m *= sizeof(PetscScalar);
432 #if defined(PETSC_HAVE_COMPLEX)
433   else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
434 #endif
435   else if (wtype == PETSC_REAL)    m *= sizeof(PetscReal);
436   else if (wtype == PETSC_DOUBLE)  m *= sizeof(double);
437   else if (wtype == PETSC_FLOAT)   m *= sizeof(float);
438   else if (wtype == PETSC_SHORT)   m *= sizeof(short);
439   else if (wtype == PETSC_LONG)    m *= sizeof(long);
440   else if (wtype == PETSC_CHAR)    m *= sizeof(char);
441   else if (wtype == PETSC_ENUM)    m *= sizeof(PetscEnum);
442   else if (wtype == PETSC_BOOL)    m *= sizeof(PetscBool);
443   else if (wtype == PETSC_INT64)   m *= sizeof(PetscInt64);
444   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
445   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
446 
447   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap((void*)ptmp,wtype,n);CHKERRQ(ierr);}
448 
449   while (m) {
450     wsize = (m < maxblock) ? m : maxblock;
451     err   = write(fd,pp,wsize);
452     if (err < 0 && errno == EINTR) continue;
453     PetscCheckFalse(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);
454     m  -= wsize;
455     pp += wsize;
456   }
457 
458   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap((void*)ptmp,wtype,n);CHKERRQ(ierr);}
459 
460   if (type == PETSC_FUNCTION) {
461     free(fname);
462   }
463 #if defined(PETSC_USE_REAL___FLOAT128)
464   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
465     ierr = PetscFree(ppp);CHKERRQ(ierr);
466   }
467 #endif
468   PetscFunctionReturn(0);
469 }
470 
471 /*@C
472    PetscBinaryOpen - Opens a PETSc binary file.
473 
474    Not Collective
475 
476    Input Parameters:
477 +  name - filename
478 -  mode - open mode of binary file, one of FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND
479 
480    Output Parameter:
481 .  fd - the file
482 
483    Level: advanced
484 
485    Notes:
486     Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
487    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
488    PetscBinaryRead() and PetscBinaryWrite() on any machine.
489 
490 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
491           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
492 
493 @*/
494 PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
495 {
496   PetscFunctionBegin;
497   switch (mode) {
498   case FILE_MODE_READ:   *fd = open(name,O_BINARY|O_RDONLY,0); break;
499   case FILE_MODE_WRITE:  *fd = open(name,O_BINARY|O_WRONLY|O_CREAT|O_TRUNC,0666); break;
500   case FILE_MODE_APPEND: *fd = open(name,O_BINARY|O_WRONLY|O_APPEND,0); break;
501   default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported file mode %s",PetscFileModes[mode]);
502   }
503   PetscCheckFalse(*fd == -1,PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file %s for %s",name,PetscFileModes[mode]);
504   PetscFunctionReturn(0);
505 }
506 
507 /*@
508    PetscBinaryClose - Closes a PETSc binary file.
509 
510    Not Collective
511 
512    Output Parameter:
513 .  fd - the file
514 
515    Level: advanced
516 
517 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
518           PetscBinarySynchronizedSeek()
519 @*/
520 PetscErrorCode  PetscBinaryClose(int fd)
521 {
522   PetscFunctionBegin;
523   PetscCheckFalse(close(fd),PETSC_COMM_SELF,PETSC_ERR_SYS,"close() failed on file descriptor");
524   PetscFunctionReturn(0);
525 }
526 
527 /*@C
528    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
529 
530    Not Collective
531 
532    Input Parameters:
533 +  fd - the file
534 .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
535             etc. in your calculation rather than sizeof() to compute byte lengths.
536 -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
537             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
538             if PETSC_BINARY_SEEK_END then off is an offset from the end of file
539 
540    Output Parameter:
541 .   offset - new offset in file
542 
543    Level: developer
544 
545    Notes:
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. Hence you CANNOT use sizeof()
549    to determine the offset or location.
550 
551 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
552           PetscBinarySynchronizedSeek()
553 @*/
554 PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
555 {
556   int iwhence = 0;
557 
558   PetscFunctionBegin;
559   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
560   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
561   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
562   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
563 #if defined(PETSC_HAVE_LSEEK)
564   *offset = lseek(fd,off,iwhence);
565 #elif defined(PETSC_HAVE__LSEEK)
566   *offset = _lseek(fd,(long)off,iwhence);
567 #else
568   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
569 #endif
570   PetscFunctionReturn(0);
571 }
572 
573 /*@C
574    PetscBinarySynchronizedRead - Reads from a binary file.
575 
576    Collective
577 
578    Input Parameters:
579 +  comm - the MPI communicator
580 .  fd - the file descriptor
581 .  num  - the maximum number of items to read
582 -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)
583 
584    Output Parameters:
585 +  data - the buffer
586 -  count - the number of items read, optional
587 
588    Level: developer
589 
590    Notes:
591    Does a PetscBinaryRead() followed by an MPI_Bcast()
592 
593    If count is not provided and the number of items read is less than
594    the maximum number of items to read, then this routine errors.
595 
596    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
597    Integers are stored on the file as 32 long, regardless of whether
598    they are stored in the machine as 32 or 64, this means the same
599    binary file may be read on any machine.
600 
601 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
602           PetscBinarySynchronizedSeek()
603 @*/
604 PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
605 {
606   PetscErrorCode ierr;
607   PetscMPIInt    rank,size;
608   MPI_Datatype   mtype;
609   PetscInt       ibuf[2] = {0, 0};
610   char           *fname = NULL;
611   void           *fptr = NULL;
612 
613   PetscFunctionBegin;
614   if (type == PETSC_FUNCTION) {
615     num   = 64;
616     type  = PETSC_CHAR;
617     fname = (char*)malloc(num*sizeof(char));
618     fptr  = data;
619     data  = (void*)fname;
620     PetscCheckFalse(!fname,PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
621   }
622 
623   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
624   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
625   if (rank == 0) {
626     ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
627   }
628   ierr = MPI_Bcast(ibuf,2,MPIU_INT,0,comm);CHKERRMPI(ierr);
629   ierr = (PetscErrorCode)ibuf[0];CHKERRQ(ierr);
630 
631   /* 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 */
632   if (size > 1) {
633     ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
634     ierr = MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);CHKERRMPI(ierr);
635   }
636   if (count) *count = ibuf[1];
637 
638   if (type == PETSC_FUNCTION) {
639 #if defined(PETSC_SERIALIZE_FUNCTIONS)
640     ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);CHKERRQ(ierr);
641 #else
642     *(void**)fptr = NULL;
643 #endif
644     free(fname);
645   }
646   PetscFunctionReturn(0);
647 }
648 
649 /*@C
650    PetscBinarySynchronizedWrite - writes to a binary file.
651 
652    Collective
653 
654    Input Parameters:
655 +  comm - the MPI communicator
656 .  fd - the file
657 .  n  - the number of items to write
658 .  p - the buffer
659 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
660 
661    Level: developer
662 
663    Notes:
664    Process 0 does a PetscBinaryWrite()
665 
666    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
667    Integers are stored on the file as 32 long, regardless of whether
668    they are stored in the machine as 32 or 64, this means the same
669    binary file may be read on any machine.
670 
671    Notes:
672     because byte-swapping may be done on the values in data it cannot be declared const
673 
674    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
675    while PetscSynchronizedFPrintf() has all processes print their strings in order.
676 
677 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
678           PetscBinarySynchronizedSeek()
679 @*/
680 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type)
681 {
682   PetscErrorCode ierr;
683   PetscMPIInt    rank;
684 
685   PetscFunctionBegin;
686   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
687   if (rank == 0) {
688     ierr = PetscBinaryWrite(fd,p,n,type);CHKERRQ(ierr);
689   }
690   PetscFunctionReturn(0);
691 }
692 
693 /*@C
694    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
695 
696    Input Parameters:
697 +  fd - the file
698 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
699             if PETSC_BINARY_SEEK_CUR then size is offset from current location
700             if PETSC_BINARY_SEEK_END then size is offset from end of file
701 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
702             etc. in your calculation rather than sizeof() to compute byte lengths.
703 
704    Output Parameter:
705 .   offset - new offset in file
706 
707    Level: developer
708 
709    Notes:
710    Integers are stored on the file as 32 long, regardless of whether
711    they are stored in the machine as 32 or 64, this means the same
712    binary file may be read on any machine. Hence you CANNOT use sizeof()
713    to determine the offset or location.
714 
715 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
716           PetscBinarySynchronizedSeek()
717 @*/
718 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
719 {
720   PetscErrorCode ierr;
721   PetscMPIInt    rank;
722 
723   PetscFunctionBegin;
724   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
725   if (rank == 0) {
726     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
727   }
728   PetscFunctionReturn(0);
729 }
730 
731 #if defined(PETSC_HAVE_MPIIO)
732 
733 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
734 /*
735       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
736     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
737 
738     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
739 
740     The next three routines are not used because MPICH does not support their use
741 
742 */
743 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
744 {
745   MPI_Aint    ub;
746   PetscMPIInt ierr;
747 
748   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
749   return ierr;
750 }
751 
752 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
753 {
754   PetscDataType pdtype;
755   PetscMPIInt   ierr;
756   size_t        dsize;
757 
758   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
759   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
760 
761   /* offset is given in units of MPI_Datatype */
762   userbuf = ((char*)userbuf) + dsize*position;
763 
764   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
765   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);}
766   return ierr;
767 }
768 
769 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
770 {
771   PetscDataType pdtype;
772   PetscMPIInt   ierr;
773   size_t        dsize;
774 
775   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
776   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
777 
778   /* offset is given in units of MPI_Datatype */
779   userbuf = ((char*)userbuf) + dsize*position;
780 
781   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
782   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);}
783   return ierr;
784 }
785 #endif
786 
787 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
788 {
789   PetscDataType  pdtype;
790   PetscErrorCode ierr;
791 
792   PetscFunctionBegin;
793   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
794   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
795   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRMPI(ierr);
796   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
797   PetscFunctionReturn(0);
798 }
799 
800 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
801 {
802   PetscDataType  pdtype;
803   PetscErrorCode ierr;
804 
805   PetscFunctionBegin;
806   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
807   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRMPI(ierr);
808   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
809   PetscFunctionReturn(0);
810 }
811 
812 PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
813 {
814   PetscDataType  pdtype;
815   PetscErrorCode ierr;
816 
817   PetscFunctionBegin;
818   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
819   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
820   ierr = MPI_File_write_at(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr);
821   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
822   PetscFunctionReturn(0);
823 }
824 
825 PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
826 {
827   PetscDataType  pdtype;
828   PetscErrorCode ierr;
829 
830   PetscFunctionBegin;
831   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
832   ierr = MPI_File_read_at(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr);
833   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
834   PetscFunctionReturn(0);
835 }
836 
837 PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
838 {
839   PetscDataType  pdtype;
840   PetscErrorCode ierr;
841 
842   PetscFunctionBegin;
843   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
844   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
845   ierr = MPI_File_write_at_all(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr);
846   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
847   PetscFunctionReturn(0);
848 }
849 
850 PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
851 {
852   PetscDataType  pdtype;
853   PetscErrorCode ierr;
854 
855   PetscFunctionBegin;
856   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
857   ierr = MPI_File_read_at_all(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr);
858   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
859   PetscFunctionReturn(0);
860 }
861 
862 #endif
863