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