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 */
PetscByteSwapEnum(PetscEnum * buff,PetscInt n)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 */
PetscByteSwapBool(PetscBool * buff,PetscInt n)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 */
PetscByteSwapInt(PetscInt * buff,PetscInt n)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 */
PetscByteSwapInt64(PetscInt64 * buff,PetscInt n)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 */
PetscByteSwapShort(short * buff,PetscInt n)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 */
PetscByteSwapLong(long * buff,PetscInt n)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 */
PetscByteSwapReal(PetscReal * buff,PetscInt n)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 */
PetscByteSwapScalar(PetscScalar * buff,PetscInt n)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 */
PetscByteSwapDouble(double * buff,PetscInt n)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 */
PetscByteSwapFloat(float * buff,PetscInt n)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
PetscByteSwap(void * data,PetscDataType pdtype,PetscInt count)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 @*/
PetscBinaryRead(int fd,void * data,PetscInt num,PetscInt * count,PetscDataType type)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 if (num < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to read a negative amount of data %D",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 if (!fname) SETERRQ(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 if (ret < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
307 m -= ret;
308 p += ret;
309 n += ret;
310 }
311 if (m && !count) SETERRQ(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
374 .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
375 PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
376 @*/
PetscBinaryWrite(int fd,const void * p,PetscInt n,PetscDataType type)377 PetscErrorCode PetscBinaryWrite(int fd,const void *p,PetscInt n,PetscDataType type)
378 {
379 const char *pp = (char*)p;
380 int err,wsize;
381 size_t m = (size_t)n,maxblock=65536;
382 PetscErrorCode ierr;
383 const void *ptmp = p;
384 char *fname = NULL;
385 #if defined(PETSC_USE_REAL___FLOAT128)
386 PetscBool writedouble = PETSC_FALSE;
387 double *ppp;
388 PetscReal *pv;
389 PetscInt i;
390 #endif
391 PetscDataType wtype = type;
392
393 PetscFunctionBegin;
394 if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
395 if (!n) PetscFunctionReturn(0);
396
397 if (type == PETSC_FUNCTION) {
398 #if defined(PETSC_SERIALIZE_FUNCTIONS)
399 const char *fnametmp;
400 #endif
401 m = 64;
402 fname = (char*)malloc(m*sizeof(char));
403 if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
404 #if defined(PETSC_SERIALIZE_FUNCTIONS)
405 if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
406 ierr = PetscFPTFind(*(void**)p,&fnametmp);CHKERRQ(ierr);
407 ierr = PetscStrncpy(fname,fnametmp,m);CHKERRQ(ierr);
408 #else
409 ierr = PetscStrncpy(fname,"",m);CHKERRQ(ierr);
410 #endif
411 wtype = PETSC_CHAR;
412 pp = (char*)fname;
413 ptmp = (void*)fname;
414 }
415
416 #if defined(PETSC_USE_REAL___FLOAT128)
417 ierr = PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);CHKERRQ(ierr);
418 /* If using __float128 precision we still write in doubles to file */
419 if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
420 wtype = PETSC_DOUBLE;
421 ierr = PetscMalloc1(n,&ppp);CHKERRQ(ierr);
422 pv = (PetscReal*)pp;
423 for (i=0; i<n; i++) {
424 ppp[i] = (double) pv[i];
425 }
426 pp = (char*)ppp;
427 ptmp = (char*)ppp;
428 }
429 #endif
430
431 if (wtype == PETSC_INT) m *= sizeof(PetscInt);
432 else if (wtype == PETSC_SCALAR) m *= sizeof(PetscScalar);
433 #if defined(PETSC_HAVE_COMPLEX)
434 else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
435 #endif
436 else if (wtype == PETSC_REAL) m *= sizeof(PetscReal);
437 else if (wtype == PETSC_DOUBLE) m *= sizeof(double);
438 else if (wtype == PETSC_FLOAT) m *= sizeof(float);
439 else if (wtype == PETSC_SHORT) m *= sizeof(short);
440 else if (wtype == PETSC_LONG) m *= sizeof(long);
441 else if (wtype == PETSC_CHAR) m *= sizeof(char);
442 else if (wtype == PETSC_ENUM) m *= sizeof(PetscEnum);
443 else if (wtype == PETSC_BOOL) m *= sizeof(PetscBool);
444 else if (wtype == PETSC_INT64) m *= sizeof(PetscInt64);
445 else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
446 else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
447
448 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap((void*)ptmp,wtype,n);CHKERRQ(ierr);}
449
450 while (m) {
451 wsize = (m < maxblock) ? m : maxblock;
452 err = write(fd,pp,wsize);
453 if (err < 0 && errno == EINTR) continue;
454 if (err != wsize) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_WRITE,"Error writing to file total size %d err %d wsize %d",(int)n,(int)err,(int)wsize);
455 m -= wsize;
456 pp += wsize;
457 }
458
459 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap((void*)ptmp,wtype,n);CHKERRQ(ierr);}
460
461 if (type == PETSC_FUNCTION) {
462 free(fname);
463 }
464 #if defined(PETSC_USE_REAL___FLOAT128)
465 if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
466 ierr = PetscFree(ppp);CHKERRQ(ierr);
467 }
468 #endif
469 PetscFunctionReturn(0);
470 }
471
472 /*@C
473 PetscBinaryOpen - Opens a PETSc binary file.
474
475 Not Collective
476
477 Input Parameters:
478 + name - filename
479 - mode - open mode of binary file, one of FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND
480
481 Output Parameter:
482 . fd - the file
483
484 Level: advanced
485
486
487 Notes:
488 Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
489 big-endian format. This means the file can be accessed using PetscBinaryOpen() and
490 PetscBinaryRead() and PetscBinaryWrite() on any machine.
491
492 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
493 PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
494
495 @*/
PetscBinaryOpen(const char name[],PetscFileMode mode,int * fd)496 PetscErrorCode PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
497 {
498 PetscFunctionBegin;
499 switch (mode) {
500 case FILE_MODE_READ: *fd = open(name,O_BINARY|O_RDONLY,0); break;
501 case FILE_MODE_WRITE: *fd = open(name,O_BINARY|O_WRONLY|O_CREAT|O_TRUNC,0666); break;
502 case FILE_MODE_APPEND: *fd = open(name,O_BINARY|O_WRONLY|O_APPEND,0); break;
503 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported file mode %s",PetscFileModes[mode]);
504 }
505 if (*fd == -1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file %s for %s: %s",name,PetscFileModes[mode]);
506 PetscFunctionReturn(0);
507 }
508
509 /*@
510 PetscBinaryClose - Closes a PETSc binary file.
511
512 Not Collective
513
514 Output Parameter:
515 . fd - the file
516
517 Level: advanced
518
519 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
520 PetscBinarySynchronizedSeek()
521 @*/
PetscBinaryClose(int fd)522 PetscErrorCode PetscBinaryClose(int fd)
523 {
524 PetscFunctionBegin;
525 if (close(fd)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"close() failed on file descriptor");
526 PetscFunctionReturn(0);
527 }
528
529
530 /*@C
531 PetscBinarySeek - Moves the file pointer on a PETSc binary file.
532
533 Not Collective
534
535 Input Parameters:
536 + fd - the file
537 . off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
538 etc. in your calculation rather than sizeof() to compute byte lengths.
539 - whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
540 if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
541 if PETSC_BINARY_SEEK_END then off is an offset from the end of file
542
543 Output Parameter:
544 . offset - new offset in file
545
546 Level: developer
547
548 Notes:
549 Integers are stored on the file as 32 long, regardless of whether
550 they are stored in the machine as 32 or 64, this means the same
551 binary file may be read on any machine. Hence you CANNOT use sizeof()
552 to determine the offset or location.
553
554
555 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
556 PetscBinarySynchronizedSeek()
557 @*/
PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t * offset)558 PetscErrorCode PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
559 {
560 int iwhence = 0;
561
562 PetscFunctionBegin;
563 if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
564 else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
565 else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
566 else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
567 #if defined(PETSC_HAVE_LSEEK)
568 *offset = lseek(fd,off,iwhence);
569 #elif defined(PETSC_HAVE__LSEEK)
570 *offset = _lseek(fd,(long)off,iwhence);
571 #else
572 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
573 #endif
574 PetscFunctionReturn(0);
575 }
576
577 /*@C
578 PetscBinarySynchronizedRead - Reads from a binary file.
579
580 Collective
581
582 Input Parameters:
583 + comm - the MPI communicator
584 . fd - the file descriptor
585 . num - the maximum number of items to read
586 - type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)
587
588 Output Parameters:
589 + data - the buffer
590 - count - the number of items read, optional
591
592 Level: developer
593
594 Notes:
595 Does a PetscBinaryRead() followed by an MPI_Bcast()
596
597 If count is not provided and the number of items read is less than
598 the maximum number of items to read, then this routine errors.
599
600 PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
601 Integers are stored on the file as 32 long, regardless of whether
602 they are stored in the machine as 32 or 64, this means the same
603 binary file may be read on any machine.
604
605
606 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
607 PetscBinarySynchronizedSeek()
608 @*/
PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void * data,PetscInt num,PetscInt * count,PetscDataType type)609 PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
610 {
611 PetscErrorCode ierr;
612 PetscMPIInt rank;
613 MPI_Datatype mtype;
614 PetscInt ibuf[2] = {0, 0};
615 char *fname = NULL;
616 void *fptr = NULL;
617
618 PetscFunctionBegin;
619 if (type == PETSC_FUNCTION) {
620 num = 64;
621 type = PETSC_CHAR;
622 fname = (char*)malloc(num*sizeof(char));
623 fptr = data;
624 data = (void*)fname;
625 if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
626 }
627
628 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
629 if (!rank) {
630 ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
631 }
632 ierr = MPI_Bcast(ibuf,2,MPIU_INT,0,comm);CHKERRQ(ierr);
633 ierr = (PetscErrorCode)ibuf[0];CHKERRQ(ierr);
634 ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
635 ierr = MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);CHKERRQ(ierr);
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
678 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
679 PetscBinarySynchronizedSeek()
680 @*/
PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void * p,PetscInt n,PetscDataType type)681 PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type)
682 {
683 PetscErrorCode ierr;
684 PetscMPIInt rank;
685
686 PetscFunctionBegin;
687 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
688 if (!rank) {
689 ierr = PetscBinaryWrite(fd,p,n,type);CHKERRQ(ierr);
690 }
691 PetscFunctionReturn(0);
692 }
693
694 /*@C
695 PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
696
697
698 Input Parameters:
699 + fd - the file
700 . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
701 if PETSC_BINARY_SEEK_CUR then size is offset from current location
702 if PETSC_BINARY_SEEK_END then size is offset from end of file
703 - off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
704 etc. in your calculation rather than sizeof() to compute byte lengths.
705
706 Output Parameter:
707 . offset - new offset in file
708
709 Level: developer
710
711 Notes:
712 Integers are stored on the file as 32 long, regardless of whether
713 they are stored in the machine as 32 or 64, this means the same
714 binary file may be read on any machine. Hence you CANNOT use sizeof()
715 to determine the offset or location.
716
717
718 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
719 PetscBinarySynchronizedSeek()
720 @*/
PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t * offset)721 PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
722 {
723 PetscErrorCode ierr;
724 PetscMPIInt rank;
725
726 PetscFunctionBegin;
727 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
728 if (!rank) {
729 ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
730 }
731 PetscFunctionReturn(0);
732 }
733
734 #if defined(PETSC_HAVE_MPIIO)
735
736 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
737 /*
738 MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
739 These are set into MPI in PetscInitialize() via MPI_Register_datarep()
740
741 Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
742
743 The next three routines are not used because MPICH does not support their use
744
745 */
PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint * file_extent,void * extra_state)746 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
747 {
748 MPI_Aint ub;
749 PetscMPIInt ierr;
750
751 ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
752 return ierr;
753 }
754
PetscDataRep_read_conv_fn(void * userbuf,MPI_Datatype datatype,PetscMPIInt count,void * filebuf,MPI_Offset position,void * extra_state)755 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
756 {
757 PetscDataType pdtype;
758 PetscMPIInt ierr;
759 size_t dsize;
760
761 ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
762 ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
763
764 /* offset is given in units of MPI_Datatype */
765 userbuf = ((char*)userbuf) + dsize*position;
766
767 ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
768 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);}
769 return ierr;
770 }
771
PetscDataRep_write_conv_fn(void * userbuf,MPI_Datatype datatype,PetscMPIInt count,void * filebuf,MPI_Offset position,void * extra_state)772 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
773 {
774 PetscDataType pdtype;
775 PetscMPIInt ierr;
776 size_t dsize;
777
778 ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
779 ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
780
781 /* offset is given in units of MPI_Datatype */
782 userbuf = ((char*)userbuf) + dsize*position;
783
784 ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
785 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);}
786 return ierr;
787 }
788 #endif
789
MPIU_File_write_all(MPI_File fd,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)790 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
791 {
792 PetscDataType pdtype;
793 PetscErrorCode ierr;
794
795
796 PetscFunctionBegin;
797 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
798 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
799 ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
800 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
801 PetscFunctionReturn(0);
802 }
803
MPIU_File_read_all(MPI_File fd,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)804 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
805 {
806 PetscDataType pdtype;
807 PetscErrorCode ierr;
808
809 PetscFunctionBegin;
810 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
811 ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
812 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
813 PetscFunctionReturn(0);
814 }
815
MPIU_File_write_at(MPI_File fd,MPI_Offset off,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)816 PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
817 {
818 PetscDataType pdtype;
819 PetscErrorCode ierr;
820
821
822 PetscFunctionBegin;
823 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
824 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
825 ierr = MPI_File_write_at(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
826 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
827 PetscFunctionReturn(0);
828 }
829
MPIU_File_read_at(MPI_File fd,MPI_Offset off,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)830 PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
831 {
832 PetscDataType pdtype;
833 PetscErrorCode ierr;
834
835 PetscFunctionBegin;
836 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
837 ierr = MPI_File_read_at(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
838 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
839 PetscFunctionReturn(0);
840 }
841
MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)842 PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
843 {
844 PetscDataType pdtype;
845 PetscErrorCode ierr;
846
847
848 PetscFunctionBegin;
849 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
850 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
851 ierr = MPI_File_write_at_all(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
852 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
853 PetscFunctionReturn(0);
854 }
855
MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)856 PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
857 {
858 PetscDataType pdtype;
859 PetscErrorCode ierr;
860
861 PetscFunctionBegin;
862 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
863 ierr = MPI_File_read_at_all(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
864 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
865 PetscFunctionReturn(0);
866 }
867
868 #endif
869