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