1 #include <petscsys.h> 2 #include <petscbt.h> 3 #include <errno.h> 4 #include <fcntl.h> 5 #if defined(PETSC_HAVE_UNISTD_H) 6 #include <unistd.h> 7 #endif 8 #if defined(PETSC_HAVE_IO_H) 9 #include <io.h> 10 #endif 11 #if !defined(PETSC_HAVE_O_BINARY) 12 #define O_BINARY 0 13 #endif 14 15 const char *const PetscFileModes[] = {"READ", "WRITE", "APPEND", "UPDATE", "APPEND_UPDATE", "PetscFileMode", "PETSC_FILE_", NULL}; 16 17 /* 18 PetscByteSwapEnum - Swap bytes in a PETSc Enum 19 20 */ 21 static PetscErrorCode PetscByteSwapEnum(PetscEnum *buff, PetscCount n) 22 { 23 PetscCount i, j; 24 PetscEnum tmp = ENUM_DUMMY; 25 char *ptr1, *ptr2 = (char *)&tmp; 26 27 PetscFunctionBegin; 28 for (j = 0; j < n; j++) { 29 ptr1 = (char *)(buff + j); 30 for (i = 0; i < (PetscCount)sizeof(PetscEnum); i++) ptr2[i] = ptr1[sizeof(PetscEnum) - 1 - i]; 31 for (i = 0; i < (PetscCount)sizeof(PetscEnum); i++) ptr1[i] = ptr2[i]; 32 } 33 PetscFunctionReturn(PETSC_SUCCESS); 34 } 35 36 /* 37 PetscByteSwapBool - Swap bytes in a PETSc Bool 38 39 */ 40 static PetscErrorCode PetscByteSwapBool(PetscBool *buff, PetscCount n) 41 { 42 PetscCount i, j; 43 PetscBool tmp = PETSC_FALSE; 44 char *ptr1, *ptr2 = (char *)&tmp; 45 46 PetscFunctionBegin; 47 for (j = 0; j < n; j++) { 48 ptr1 = (char *)(buff + j); 49 for (i = 0; i < (PetscCount)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool) - 1 - i]; 50 for (i = 0; i < (PetscCount)sizeof(PetscBool); i++) ptr1[i] = ptr2[i]; 51 } 52 PetscFunctionReturn(PETSC_SUCCESS); 53 } 54 55 /* 56 PetscByteSwapInt - Swap bytes in a PETSc integer (which may be 32 or 64-bits) 57 58 */ 59 static PetscErrorCode PetscByteSwapInt(PetscInt *buff, PetscCount n) 60 { 61 PetscCount i, j; 62 PetscInt tmp = 0; 63 char *ptr1, *ptr2 = (char *)&tmp; 64 65 PetscFunctionBegin; 66 for (j = 0; j < n; j++) { 67 ptr1 = (char *)(buff + j); 68 for (i = 0; i < (PetscCount)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt) - 1 - i]; 69 for (i = 0; i < (PetscCount)sizeof(PetscInt); i++) ptr1[i] = ptr2[i]; 70 } 71 PetscFunctionReturn(PETSC_SUCCESS); 72 } 73 74 /* 75 PetscByteSwapInt64 - Swap bytes in a PETSc integer (64-bits) 76 77 */ 78 static PetscErrorCode PetscByteSwapInt64(PetscInt64 *buff, PetscCount n) 79 { 80 PetscCount i, j; 81 PetscInt64 tmp = 0; 82 char *ptr1, *ptr2 = (char *)&tmp; 83 84 PetscFunctionBegin; 85 for (j = 0; j < n; j++) { 86 ptr1 = (char *)(buff + j); 87 for (i = 0; i < (PetscCount)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64) - 1 - i]; 88 for (i = 0; i < (PetscCount)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i]; 89 } 90 PetscFunctionReturn(PETSC_SUCCESS); 91 } 92 93 /* 94 PetscByteSwapInt32 - Swap bytes in a PETSc integer (32-bits) 95 96 */ 97 static PetscErrorCode PetscByteSwapInt32(PetscInt32 *buff, PetscCount n) 98 { 99 PetscCount i, j; 100 PetscInt32 tmp = 0; 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 < (PetscCount)sizeof(PetscInt32); i++) ptr2[i] = ptr1[sizeof(PetscInt32) - 1 - i]; 107 for (i = 0; i < (PetscCount)sizeof(PetscInt32); i++) ptr1[i] = ptr2[i]; 108 } 109 PetscFunctionReturn(PETSC_SUCCESS); 110 } 111 112 /* 113 PetscByteSwapShort - Swap bytes in a short 114 */ 115 static PetscErrorCode PetscByteSwapShort(short *buff, PetscCount n) 116 { 117 PetscCount i, j; 118 short tmp; 119 char *ptr1, *ptr2 = (char *)&tmp; 120 121 PetscFunctionBegin; 122 for (j = 0; j < n; j++) { 123 ptr1 = (char *)(buff + j); 124 for (i = 0; i < (PetscCount)sizeof(short); i++) ptr2[i] = ptr1[sizeof(short) - 1 - i]; 125 for (i = 0; i < (PetscCount)sizeof(short); i++) ptr1[i] = ptr2[i]; 126 } 127 PetscFunctionReturn(PETSC_SUCCESS); 128 } 129 /* 130 PetscByteSwapLong - Swap bytes in a long 131 */ 132 static PetscErrorCode PetscByteSwapLong(long *buff, PetscCount n) 133 { 134 PetscCount i, j; 135 long tmp; 136 char *ptr1, *ptr2 = (char *)&tmp; 137 138 PetscFunctionBegin; 139 for (j = 0; j < n; j++) { 140 ptr1 = (char *)(buff + j); 141 for (i = 0; i < (PetscCount)sizeof(long); i++) ptr2[i] = ptr1[sizeof(long) - 1 - i]; 142 for (i = 0; i < (PetscCount)sizeof(long); i++) ptr1[i] = ptr2[i]; 143 } 144 PetscFunctionReturn(PETSC_SUCCESS); 145 } 146 147 /* 148 PetscByteSwapReal - Swap bytes in a PetscReal 149 */ 150 static PetscErrorCode PetscByteSwapReal(PetscReal *buff, PetscCount n) 151 { 152 PetscCount i, j; 153 PetscReal tmp, *buff1 = (PetscReal *)buff; 154 char *ptr1, *ptr2 = (char *)&tmp; 155 156 PetscFunctionBegin; 157 for (j = 0; j < n; j++) { 158 ptr1 = (char *)(buff1 + j); 159 for (i = 0; i < (PetscCount)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i]; 160 for (i = 0; i < (PetscCount)sizeof(PetscReal); i++) ptr1[i] = ptr2[i]; 161 } 162 PetscFunctionReturn(PETSC_SUCCESS); 163 } 164 165 /* 166 PetscByteSwapScalar - Swap bytes in a PetscScalar 167 The complex case is dealt with an array of PetscReal, twice as long. 168 */ 169 static PetscErrorCode PetscByteSwapScalar(PetscScalar *buff, PetscCount n) 170 { 171 PetscCount i, j; 172 PetscReal tmp, *buff1 = (PetscReal *)buff; 173 char *ptr1, *ptr2 = (char *)&tmp; 174 175 PetscFunctionBegin; 176 #if defined(PETSC_USE_COMPLEX) 177 n *= 2; 178 #endif 179 for (j = 0; j < n; j++) { 180 ptr1 = (char *)(buff1 + j); 181 for (i = 0; i < (PetscCount)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i]; 182 for (i = 0; i < (PetscCount)sizeof(PetscReal); i++) ptr1[i] = ptr2[i]; 183 } 184 PetscFunctionReturn(PETSC_SUCCESS); 185 } 186 187 /* 188 PetscByteSwapDouble - Swap bytes in a double 189 */ 190 static PetscErrorCode PetscByteSwapDouble(double *buff, PetscCount n) 191 { 192 PetscCount i, j; 193 double tmp, *buff1 = (double *)buff; 194 char *ptr1, *ptr2 = (char *)&tmp; 195 196 PetscFunctionBegin; 197 for (j = 0; j < n; j++) { 198 ptr1 = (char *)(buff1 + j); 199 for (i = 0; i < (PetscCount)sizeof(double); i++) ptr2[i] = ptr1[sizeof(double) - 1 - i]; 200 for (i = 0; i < (PetscCount)sizeof(double); i++) ptr1[i] = ptr2[i]; 201 } 202 PetscFunctionReturn(PETSC_SUCCESS); 203 } 204 205 /* 206 PetscByteSwapFloat - Swap bytes in a float 207 */ 208 static PetscErrorCode PetscByteSwapFloat(float *buff, PetscCount n) 209 { 210 PetscCount i, j; 211 float tmp, *buff1 = (float *)buff; 212 char *ptr1, *ptr2 = (char *)&tmp; 213 214 PetscFunctionBegin; 215 for (j = 0; j < n; j++) { 216 ptr1 = (char *)(buff1 + j); 217 for (i = 0; i < (PetscCount)sizeof(float); i++) ptr2[i] = ptr1[sizeof(float) - 1 - i]; 218 for (i = 0; i < (PetscCount)sizeof(float); i++) ptr1[i] = ptr2[i]; 219 } 220 PetscFunctionReturn(PETSC_SUCCESS); 221 } 222 223 PetscErrorCode PetscByteSwap(void *data, PetscDataType pdtype, PetscCount count) 224 { 225 PetscFunctionBegin; 226 if (pdtype == PETSC_INT) PetscCall(PetscByteSwapInt((PetscInt *)data, count)); 227 else if (pdtype == PETSC_ENUM) PetscCall(PetscByteSwapEnum((PetscEnum *)data, count)); 228 else if (pdtype == PETSC_BOOL) PetscCall(PetscByteSwapBool((PetscBool *)data, count)); 229 else if (pdtype == PETSC_SCALAR) PetscCall(PetscByteSwapScalar((PetscScalar *)data, count)); 230 else if (pdtype == PETSC_REAL) PetscCall(PetscByteSwapReal((PetscReal *)data, count)); 231 else if (pdtype == PETSC_COMPLEX) PetscCall(PetscByteSwapReal((PetscReal *)data, 2 * count)); 232 else if (pdtype == PETSC_INT64) PetscCall(PetscByteSwapInt64((PetscInt64 *)data, count)); 233 else if (pdtype == PETSC_COUNT) PetscCall(PetscByteSwapInt64((PetscInt64 *)data, count)); 234 else if (pdtype == PETSC_INT32) PetscCall(PetscByteSwapInt32((PetscInt32 *)data, count)); 235 else if (pdtype == PETSC_DOUBLE) PetscCall(PetscByteSwapDouble((double *)data, count)); 236 else if (pdtype == PETSC_FLOAT) PetscCall(PetscByteSwapFloat((float *)data, count)); 237 else if (pdtype == PETSC_SHORT) PetscCall(PetscByteSwapShort((short *)data, count)); 238 else if (pdtype == PETSC_LONG) PetscCall(PetscByteSwapLong((long *)data, count)); 239 else if (pdtype == PETSC_CHAR) PetscFunctionReturn(PETSC_SUCCESS); 240 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown type: %d", pdtype); 241 PetscFunctionReturn(PETSC_SUCCESS); 242 } 243 244 /*@C 245 PetscBinaryRead - Reads from a binary file. 246 247 Not Collective 248 249 Input Parameters: 250 + fd - the file descriptor 251 . num - the maximum number of items to read 252 - type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.) 253 254 Output Parameters: 255 + data - the buffer, this is an array of the type that matches the value in `type` 256 - count - the number of items read, optional 257 258 Level: developer 259 260 Notes: 261 If `count` is not provided and the number of items read is less than 262 the maximum number of items to read, then this routine errors. 263 264 `PetscBinaryRead()` uses byte swapping to work on all machines; the files 265 are written ALWAYS using big-endian ordering. On little-endian machines the numbers 266 are converted to the little-endian format when they are read in from the file. 267 When PETSc is ./configure with `--with-64-bit-indices` the integers are written to the 268 file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices` 269 is used. 270 271 Fortran Note: 272 There are different functions for each datatype, for example `PetscBinaryReadInt()` 273 274 .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`, 275 `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()` 276 @*/ 277 PetscErrorCode PetscBinaryRead(int fd, void *data, PetscCount num, PetscInt *count, PetscDataType type) 278 { 279 size_t typesize, m = (size_t)num, n = 0, maxblock = 65536; 280 char *p = (char *)data; 281 #if defined(PETSC_USE_REAL___FLOAT128) 282 PetscBool readdouble = PETSC_FALSE; 283 double *pdouble; 284 #endif 285 void *ptmp = data; 286 char *fname = NULL; 287 288 PetscFunctionBegin; 289 if (count) *count = 0; 290 PetscCheck(num >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to read a negative amount of data %" PetscCount_FMT, num); 291 if (!num) PetscFunctionReturn(PETSC_SUCCESS); 292 293 if (type == PETSC_FUNCTION) { 294 m = 64; 295 type = PETSC_CHAR; 296 fname = (char *)malloc(m * sizeof(char)); 297 p = (char *)fname; 298 ptmp = (void *)fname; 299 PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name"); 300 } 301 if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(num); 302 303 PetscCall(PetscDataTypeGetSize(type, &typesize)); 304 305 #if defined(PETSC_USE_REAL___FLOAT128) 306 PetscCall(PetscOptionsGetBool(NULL, NULL, "-binary_read_double", &readdouble, NULL)); 307 /* If using __float128 precision we still read in doubles from file */ 308 if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) { 309 PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2); 310 PetscCall(PetscMalloc1(cnt, &pdouble)); 311 p = (char *)pdouble; 312 typesize /= 2; 313 } 314 #endif 315 316 m *= typesize; 317 318 while (m) { 319 size_t len = (m < maxblock) ? m : maxblock; 320 int ret = (int)read(fd, p, len); 321 if (ret < 0 && errno == EINTR) continue; 322 if (!ret && len > 0) break; /* Proxy for EOF */ 323 PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file due to \"%s\"", strerror(errno)); 324 m -= (size_t)ret; 325 p += ret; 326 n += (size_t)ret; 327 } 328 PetscCheck(!m || count, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Read past end of file"); 329 330 num = n / typesize; /* Should we require `n % typesize == 0` ? */ 331 if (count) PetscCall(PetscIntCast(num, count)); /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */ 332 333 #if defined(PETSC_USE_REAL___FLOAT128) 334 if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) { 335 PetscInt i, cnt = num * ((type == PETSC_REAL) ? 1 : 2); 336 PetscReal *preal = (PetscReal *)data; 337 if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwapDouble(pdouble, cnt)); 338 for (i = 0; i < cnt; i++) preal[i] = pdouble[i]; 339 PetscCall(PetscFree(pdouble)); 340 PetscFunctionReturn(PETSC_SUCCESS); 341 } 342 #endif 343 344 if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(ptmp, type, num)); 345 346 if (type == PETSC_FUNCTION) { 347 #if defined(PETSC_SERIALIZE_FUNCTIONS) 348 PetscCall(PetscDLSym(NULL, fname, (void **)data)); 349 #else 350 *(void **)data = NULL; 351 #endif 352 free(fname); 353 } 354 PetscFunctionReturn(PETSC_SUCCESS); 355 } 356 357 /*@C 358 PetscBinaryWrite - Writes to a binary file. 359 360 Not Collective 361 362 Input Parameters: 363 + fd - the file 364 . p - the buffer, an array of the type that matches the value in `type` 365 . n - the number of items to write 366 - type - the type of items to read (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`) 367 368 Level: advanced 369 370 Notes: 371 `PetscBinaryWrite()` uses byte swapping to work on all machines; the files 372 are written using big-endian ordering to the file. On little-endian machines the numbers 373 are converted to the big-endian format when they are written to disk. 374 When PETSc is configured using `./configure with --with-64-bit-indices` the integers are written to the 375 file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices` 376 is used. 377 378 If running with `__float128` precision the output of `PETSC_REAL` is in `__float128` unless one uses the `-binary_write_double` option 379 380 The buffer `p` should be read-write buffer, and not static data. 381 This way, byte-swapping is done in-place, and then the buffer is 382 written to the file. 383 384 This routine restores the original contents of the buffer, after 385 it is written to the file. This is done by byte-swapping in-place 386 the second time. 387 388 Because byte-swapping may be done on the values in data it cannot be declared const 389 390 Fortran Note: 391 There are different functions for each datatype, for example `PetscBinaryWriteInt()` 392 393 .seealso: `PetscBinaryRead()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`, 394 `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()` 395 @*/ 396 PetscErrorCode PetscBinaryWrite(int fd, const void *p, PetscCount n, PetscDataType type) 397 { 398 const char *pp = (char *)p; 399 size_t err, m = (size_t)n, wsize; 400 const size_t maxblock = 65536; 401 const void *ptmp = p; 402 char *fname = NULL; 403 #if defined(PETSC_USE_REAL___FLOAT128) 404 PetscBool writedouble = PETSC_FALSE; 405 double *ppp; 406 PetscReal *pv; 407 #endif 408 PetscDataType wtype = type; 409 410 PetscFunctionBegin; 411 PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to write a negative amount of data %" PetscCount_FMT, n); 412 if (!n) PetscFunctionReturn(PETSC_SUCCESS); 413 414 if (type == PETSC_FUNCTION) { 415 #if defined(PETSC_SERIALIZE_FUNCTIONS) 416 const char *fnametmp; 417 #endif 418 m = 64; 419 fname = (char *)malloc(m * sizeof(char)); 420 PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name"); 421 #if defined(PETSC_SERIALIZE_FUNCTIONS) 422 PetscCheck(n <= 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only binary view a single function at a time"); 423 PetscCall(PetscFPTFind(*(void **)p, &fnametmp)); 424 PetscCall(PetscStrncpy(fname, fnametmp, m)); 425 #else 426 PetscCall(PetscStrncpy(fname, "", m)); 427 #endif 428 wtype = PETSC_CHAR; 429 pp = (char *)fname; 430 ptmp = (void *)fname; 431 } 432 433 #if defined(PETSC_USE_REAL___FLOAT128) 434 PetscCall(PetscOptionsGetBool(NULL, NULL, "-binary_write_double", &writedouble, NULL)); 435 /* If using __float128 precision we still write in doubles to file */ 436 if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) { 437 wtype = PETSC_DOUBLE; 438 PetscCall(PetscMalloc1(n, &ppp)); 439 pv = (PetscReal *)pp; 440 for (PetscCount i = 0; i < n; i++) ppp[i] = (double)pv[i]; 441 pp = (char *)ppp; 442 ptmp = (char *)ppp; 443 } 444 #endif 445 446 if (wtype == PETSC_INT) m *= sizeof(PetscInt); 447 else if (wtype == PETSC_SCALAR) m *= sizeof(PetscScalar); 448 #if defined(PETSC_HAVE_COMPLEX) 449 else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex); 450 #endif 451 else if (wtype == PETSC_REAL) m *= sizeof(PetscReal); 452 else if (wtype == PETSC_DOUBLE) m *= sizeof(double); 453 else if (wtype == PETSC_FLOAT) m *= sizeof(float); 454 else if (wtype == PETSC_SHORT) m *= sizeof(short); 455 else if (wtype == PETSC_LONG) m *= sizeof(long); 456 else if (wtype == PETSC_CHAR) m *= sizeof(char); 457 else if (wtype == PETSC_ENUM) m *= sizeof(PetscEnum); 458 else if (wtype == PETSC_BOOL) m *= sizeof(PetscBool); 459 else if (wtype == PETSC_INT64) m *= sizeof(PetscInt64); 460 else if (wtype == PETSC_INT32) m *= sizeof(PetscInt32); 461 else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m) * sizeof(char); 462 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown type: %d", wtype); 463 464 if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap((void *)ptmp, wtype, n)); 465 466 while (m) { 467 wsize = (m < maxblock) ? m : maxblock; 468 err = (size_t)write(fd, pp, wsize); 469 if (errno == EINTR) continue; 470 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)); 471 m -= wsize; 472 pp += wsize; 473 } 474 475 if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap((void *)ptmp, wtype, n)); 476 477 if (type == PETSC_FUNCTION) free(fname); 478 #if defined(PETSC_USE_REAL___FLOAT128) 479 if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) PetscCall(PetscFree(ppp)); 480 #endif 481 PetscFunctionReturn(PETSC_SUCCESS); 482 } 483 484 /*@ 485 PetscBinaryOpen - Opens a PETSc binary file. 486 487 Not Collective 488 489 Input Parameters: 490 + name - filename 491 - mode - open mode of binary file, one of `FILE_MODE_READ`, `FILE_MODE_WRITE`, `FILE_MODE_APPEND` 492 493 Output Parameter: 494 . fd - the file 495 496 Level: advanced 497 498 .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscFileMode`, `PetscViewerFileSetMode()`, `PetscViewerBinaryGetDescriptor()`, 499 `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()` 500 @*/ 501 PetscErrorCode PetscBinaryOpen(const char name[], PetscFileMode mode, int *fd) 502 { 503 PetscFunctionBegin; 504 switch (mode) { 505 case FILE_MODE_READ: 506 *fd = open(name, O_BINARY | O_RDONLY, 0); 507 break; 508 case FILE_MODE_WRITE: 509 *fd = open(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666); 510 break; 511 case FILE_MODE_APPEND: 512 *fd = open(name, O_BINARY | O_WRONLY | O_APPEND, 0); 513 break; 514 default: 515 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[mode]); 516 } 517 PetscCheck(*fd != -1, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open file %s for %s due to \"%s\"", name, PetscFileModes[mode], strerror(errno)); 518 PetscFunctionReturn(PETSC_SUCCESS); 519 } 520 521 /*@ 522 PetscBinaryClose - Closes a PETSc binary file. 523 524 Not Collective 525 526 Output Parameter: 527 . fd - the file 528 529 Level: advanced 530 531 .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`, 532 `PetscBinarySynchronizedSeek()` 533 @*/ 534 PetscErrorCode PetscBinaryClose(int fd) 535 { 536 PetscFunctionBegin; 537 PetscCheck(!close(fd), PETSC_COMM_SELF, PETSC_ERR_SYS, "close() failed on file descriptor"); 538 PetscFunctionReturn(PETSC_SUCCESS); 539 } 540 541 /*@C 542 PetscBinarySeek - Moves the file pointer on a PETSc binary file. 543 544 Not Collective, No Fortran Support 545 546 Input Parameters: 547 + fd - the file 548 . off - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`, 549 etc. in your calculation rather than `sizeof()` to compute byte lengths. 550 - whence - see `PetscBinarySeekType` for possible values 551 552 Output Parameter: 553 . offset - new offset in file 554 555 Level: developer 556 557 .seealso: `PetscBinaryRead()`, `PetscBinarySeekType`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`, 558 `PetscBinarySynchronizedSeek()` 559 @*/ 560 PetscErrorCode PetscBinarySeek(int fd, off_t off, PetscBinarySeekType whence, off_t *offset) 561 { 562 int iwhence = 0; 563 564 PetscFunctionBegin; 565 if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET; 566 else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR; 567 else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END; 568 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown seek location"); 569 #if defined(PETSC_HAVE_LSEEK) 570 *offset = lseek(fd, off, iwhence); 571 #elif defined(PETSC_HAVE__LSEEK) 572 *offset = _lseek(fd, (long)off, iwhence); 573 #else 574 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "System does not have a way of seeking on a file"); 575 #endif 576 PetscFunctionReturn(PETSC_SUCCESS); 577 } 578 579 /*@C 580 PetscBinarySynchronizedRead - Reads from a binary file, all MPI processes get the same values 581 582 Collective, No Fortran Support 583 584 Input Parameters: 585 + comm - the MPI communicator 586 . fd - the file descriptor 587 . num - the maximum number of items to read 588 - type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.) 589 590 Output Parameters: 591 + data - the buffer, an array of the type that matches the value in `type` 592 - count - the number of items read, optional 593 594 Level: developer 595 596 Notes: 597 Does a `PetscBinaryRead()` followed by an `MPI_Bcast()` 598 599 If `count` is not provided and the number of items read is less than 600 the maximum number of items to read, then this routine errors. 601 602 `PetscBinarySynchronizedRead()` uses byte swapping to work on all machines. 603 The files are written using big-endian ordering to the file. On little-endian machines the numbers 604 are converted to the big-endian format when they are written to disk. 605 When PETSc is configured using `./configure with --with-64-bit-indices` the integers are written to the 606 file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices` 607 is used. 608 609 .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedWrite()`, 610 `PetscBinarySynchronizedSeek()` 611 @*/ 612 PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm, int fd, void *data, PetscInt num, PetscInt *count, PetscDataType type) 613 { 614 PetscMPIInt rank, size; 615 MPI_Datatype mtype; 616 PetscInt ibuf[2] = {0, 0}; 617 char *fname = NULL; 618 void *fptr = NULL; 619 620 PetscFunctionBegin; 621 if (type == PETSC_FUNCTION) { 622 num = 64; 623 type = PETSC_CHAR; 624 fname = (char *)malloc(num * sizeof(char)); 625 fptr = data; 626 data = (void *)fname; 627 PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name"); 628 } 629 630 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 631 PetscCallMPI(MPI_Comm_size(comm, &size)); 632 if (rank == 0) ibuf[0] = (PetscInt)PetscBinaryRead(fd, data, num, count ? &ibuf[1] : NULL, type); 633 PetscCallMPI(MPI_Bcast(ibuf, 2, MPIU_INT, 0, comm)); 634 PetscCall((PetscErrorCode)ibuf[0]); 635 636 /* skip MPI call on potentially huge amounts of data when running with one process; this allows the amount of data to basically unlimited in that case */ 637 if (size > 1) { 638 PetscMPIInt cnt; 639 640 PetscCall(PetscMPIIntCast(count ? ibuf[1] : num, &cnt)); 641 PetscCall(PetscDataTypeToMPIDataType(type, &mtype)); 642 PetscCallMPI(MPI_Bcast(data, cnt, 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