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 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 @*/ 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 @*/ 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 @*/ 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 @*/ 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 @*/ 609 PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type) 610 { 611 PetscErrorCode ierr; 612 PetscMPIInt rank,size; 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);CHKERRMPI(ierr); 629 ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr); 630 if (!rank) { 631 ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type); 632 } 633 ierr = MPI_Bcast(ibuf,2,MPIU_INT,0,comm);CHKERRMPI(ierr); 634 ierr = (PetscErrorCode)ibuf[0];CHKERRQ(ierr); 635 636 /* 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 */ 637 if (size > 1) { 638 ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr); 639 ierr = MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);CHKERRMPI(ierr); 640 } 641 if (count) *count = ibuf[1]; 642 643 if (type == PETSC_FUNCTION) { 644 #if defined(PETSC_SERIALIZE_FUNCTIONS) 645 ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);CHKERRQ(ierr); 646 #else 647 *(void**)fptr = NULL; 648 #endif 649 free(fname); 650 } 651 PetscFunctionReturn(0); 652 } 653 654 /*@C 655 PetscBinarySynchronizedWrite - writes to a binary file. 656 657 Collective 658 659 Input Parameters: 660 + comm - the MPI communicator 661 . fd - the file 662 . n - the number of items to write 663 . p - the buffer 664 - type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR) 665 666 Level: developer 667 668 Notes: 669 Process 0 does a PetscBinaryWrite() 670 671 PetscBinarySynchronizedWrite() uses byte swapping to work on all machines. 672 Integers are stored on the file as 32 long, regardless of whether 673 they are stored in the machine as 32 or 64, this means the same 674 binary file may be read on any machine. 675 676 Notes: 677 because byte-swapping may be done on the values in data it cannot be declared const 678 679 WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0, 680 while PetscSynchronizedFPrintf() has all processes print their strings in order. 681 682 683 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(), 684 PetscBinarySynchronizedSeek() 685 @*/ 686 PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type) 687 { 688 PetscErrorCode ierr; 689 PetscMPIInt rank; 690 691 PetscFunctionBegin; 692 ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr); 693 if (!rank) { 694 ierr = PetscBinaryWrite(fd,p,n,type);CHKERRQ(ierr); 695 } 696 PetscFunctionReturn(0); 697 } 698 699 /*@C 700 PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file. 701 702 703 Input Parameters: 704 + fd - the file 705 . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file 706 if PETSC_BINARY_SEEK_CUR then size is offset from current location 707 if PETSC_BINARY_SEEK_END then size is offset from end of file 708 - off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE, 709 etc. in your calculation rather than sizeof() to compute byte lengths. 710 711 Output Parameter: 712 . offset - new offset in file 713 714 Level: developer 715 716 Notes: 717 Integers are stored on the file as 32 long, regardless of whether 718 they are stored in the machine as 32 or 64, this means the same 719 binary file may be read on any machine. Hence you CANNOT use sizeof() 720 to determine the offset or location. 721 722 723 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), 724 PetscBinarySynchronizedSeek() 725 @*/ 726 PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset) 727 { 728 PetscErrorCode ierr; 729 PetscMPIInt rank; 730 731 PetscFunctionBegin; 732 ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr); 733 if (!rank) { 734 ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr); 735 } 736 PetscFunctionReturn(0); 737 } 738 739 #if defined(PETSC_HAVE_MPIIO) 740 741 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32) 742 /* 743 MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions. 744 These are set into MPI in PetscInitialize() via MPI_Register_datarep() 745 746 Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode) 747 748 The next three routines are not used because MPICH does not support their use 749 750 */ 751 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state) 752 { 753 MPI_Aint ub; 754 PetscMPIInt ierr; 755 756 ierr = MPI_Type_get_extent(datatype,&ub,file_extent); 757 return ierr; 758 } 759 760 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state) 761 { 762 PetscDataType pdtype; 763 PetscMPIInt ierr; 764 size_t dsize; 765 766 ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr); 767 ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr); 768 769 /* offset is given in units of MPI_Datatype */ 770 userbuf = ((char*)userbuf) + dsize*position; 771 772 ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr); 773 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);} 774 return ierr; 775 } 776 777 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state) 778 { 779 PetscDataType pdtype; 780 PetscMPIInt ierr; 781 size_t dsize; 782 783 ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr); 784 ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr); 785 786 /* offset is given in units of MPI_Datatype */ 787 userbuf = ((char*)userbuf) + dsize*position; 788 789 ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr); 790 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);} 791 return ierr; 792 } 793 #endif 794 795 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) 796 { 797 PetscDataType pdtype; 798 PetscErrorCode ierr; 799 800 801 PetscFunctionBegin; 802 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); 803 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 804 ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRMPI(ierr); 805 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 806 PetscFunctionReturn(0); 807 } 808 809 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) 810 { 811 PetscDataType pdtype; 812 PetscErrorCode ierr; 813 814 PetscFunctionBegin; 815 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); 816 ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRMPI(ierr); 817 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 818 PetscFunctionReturn(0); 819 } 820 821 PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) 822 { 823 PetscDataType pdtype; 824 PetscErrorCode ierr; 825 826 827 PetscFunctionBegin; 828 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); 829 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 830 ierr = MPI_File_write_at(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr); 831 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 832 PetscFunctionReturn(0); 833 } 834 835 PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) 836 { 837 PetscDataType pdtype; 838 PetscErrorCode ierr; 839 840 PetscFunctionBegin; 841 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); 842 ierr = MPI_File_read_at(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr); 843 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 844 PetscFunctionReturn(0); 845 } 846 847 PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) 848 { 849 PetscDataType pdtype; 850 PetscErrorCode ierr; 851 852 853 PetscFunctionBegin; 854 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); 855 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 856 ierr = MPI_File_write_at_all(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr); 857 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 858 PetscFunctionReturn(0); 859 } 860 861 PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) 862 { 863 PetscDataType pdtype; 864 PetscErrorCode ierr; 865 866 PetscFunctionBegin; 867 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); 868 ierr = MPI_File_read_at_all(fd,off,data,cnt,dtype,status);CHKERRMPI(ierr); 869 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 870 PetscFunctionReturn(0); 871 } 872 873 #endif 874