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