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