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