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