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