1 /* 2 Utilities routines to add simple ASCII IO capability. 3 */ 4 #include <../src/sys/fileio/mprint.h> 5 #include <errno.h> 6 /* 7 If petsc_history is on, then all Petsc*Printf() results are saved 8 if the appropriate (usually .petschistory) file. 9 */ 10 PETSC_INTERN FILE *petsc_history; 11 /* 12 Allows one to overwrite where standard out is sent. For example 13 PETSC_STDOUT = fopen("/dev/ttyXX","w") will cause all standard out 14 writes to go to terminal XX; assuming you have write permission there 15 */ 16 FILE *PETSC_STDOUT = NULL; 17 /* 18 Allows one to overwrite where standard error is sent. For example 19 PETSC_STDERR = fopen("/dev/ttyXX","w") will cause all standard error 20 writes to go to terminal XX; assuming you have write permission there 21 */ 22 FILE *PETSC_STDERR = NULL; 23 24 /*@C 25 PetscFormatConvertGetSize - Gets the length of a string needed to hold data converted with `PetscFormatConvert()` based on the format 26 27 No Fortran Support 28 29 Input Parameter: 30 . format - the PETSc format string 31 32 Output Parameter: 33 . size - the needed length of the new format 34 35 Level: developer 36 37 .seealso: `PetscFormatConvert()`, `PetscVSNPrintf()`, `PetscVFPrintf()` 38 @*/ 39 PetscErrorCode PetscFormatConvertGetSize(const char *format, size_t *size) 40 { 41 size_t sz = 0; 42 PetscInt i = 0; 43 44 PetscFunctionBegin; 45 PetscAssertPointer(format, 1); 46 PetscAssertPointer(size, 2); 47 while (format[i]) { 48 if (format[i] == '%') { 49 if (format[i + 1] == '%') { 50 i += 2; 51 sz += 2; 52 continue; 53 } 54 /* Find the letter */ 55 while (format[i] && (format[i] <= '9')) { 56 ++i; 57 ++sz; 58 } 59 switch (format[i]) { 60 #if PetscDefined(USE_64BIT_INDICES) 61 case 'D': 62 sz += 2; 63 break; 64 #endif 65 case 'g': 66 sz += 4; 67 default: 68 break; 69 } 70 } 71 ++i; 72 ++sz; 73 } 74 *size = sz + 1; /* space for NULL character */ 75 PetscFunctionReturn(PETSC_SUCCESS); 76 } 77 78 /*@C 79 PetscFormatConvert - converts %g to [|%g|] so that `PetscVSNPrintf()` can ensure all %g formatted numbers have a decimal point when printed. 80 81 No Fortran Support 82 83 Input Parameter: 84 . format - the PETSc format string 85 86 Output Parameter: 87 . newformat - the formatted string 88 89 Level: developer 90 91 Note: 92 The decimal point is then used by the `petscdiff` script so that differences in floating 93 point number output is ignored in the test harness. 94 95 Deprecated usage also converts the `%D` to `%d` for 32-bit PETSc indices and to `%lld` for 96 64-bit PETSc indices. This feature is no longer used in PETSc code instead use %" 97 PetscInt_FMT " in the format string. 98 99 .seealso: `PetscFormatConvertGetSize()`, `PetscVSNPrintf()`, `PetscVFPrintf()` 100 @*/ 101 PetscErrorCode PetscFormatConvert(const char *format, char *newformat) 102 { 103 PetscInt i = 0, j = 0; 104 105 PetscFunctionBegin; 106 while (format[i]) { 107 if (format[i] == '%' && format[i + 1] == '%') { 108 newformat[j++] = format[i++]; 109 newformat[j++] = format[i++]; 110 } else if (format[i] == '%') { 111 if (format[i + 1] == 'g') { 112 newformat[j++] = '['; 113 newformat[j++] = '|'; 114 } 115 /* Find the letter */ 116 for (; format[i] && format[i] <= '9'; i++) newformat[j++] = format[i]; 117 switch (format[i]) { 118 case 'D': 119 #if !defined(PETSC_USE_64BIT_INDICES) 120 newformat[j++] = 'd'; 121 #else 122 newformat[j++] = 'l'; 123 newformat[j++] = 'l'; 124 newformat[j++] = 'd'; 125 #endif 126 break; 127 case 'g': 128 newformat[j++] = format[i]; 129 if (format[i - 1] == '%') { 130 newformat[j++] = '|'; 131 newformat[j++] = ']'; 132 } 133 break; 134 case 'G': 135 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "%%G format is no longer supported, use %%g and cast the argument to double"); 136 case 'F': 137 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "%%F format is no longer supported, use %%f and cast the argument to double"); 138 default: 139 newformat[j++] = format[i]; 140 break; 141 } 142 i++; 143 } else newformat[j++] = format[i++]; 144 } 145 newformat[j] = 0; 146 PetscFunctionReturn(PETSC_SUCCESS); 147 } 148 149 #define PETSCDEFAULTBUFFERSIZE 8 * 1024 150 151 /*@C 152 PetscVSNPrintf - The PETSc version of `vsnprintf()`. Ensures that all `%g` formatted arguments' output contains the decimal point (which 153 is used by the test harness) 154 155 Input Parameters: 156 + str - location to put result 157 . len - the length of `str` 158 . format - the PETSc format string 159 - Argp - the variable argument list to format 160 161 Output Parameter: 162 . fullLength - the amount of space in `str` actually used. 163 164 Level: developer 165 166 Developer Notes: 167 This function may be called from an error handler, if an error occurs when it is called by the error handler than likely 168 a recursion will occur resulting in a crash of the program. 169 170 If the length of the format string `format` is on the order of `PETSCDEFAULTBUFFERSIZE` (8 * 1024 bytes) or larger, this function will call `PetscMalloc()` 171 172 .seealso: `PetscFormatConvert()`, `PetscFormatConvertGetSize()`, `PetscErrorPrintf()`, `PetscVPrintf()` 173 @*/ 174 PetscErrorCode PetscVSNPrintf(char *str, size_t len, const char *format, size_t *fullLength, va_list Argp) 175 { 176 char *newformat = NULL; 177 char formatbuf[PETSCDEFAULTBUFFERSIZE]; 178 size_t newLength; 179 int flen; 180 181 PetscFunctionBegin; 182 PetscCall(PetscFormatConvertGetSize(format, &newLength)); 183 if (newLength < sizeof(formatbuf)) { 184 newformat = formatbuf; 185 newLength = sizeof(formatbuf) - 1; 186 } else { 187 PetscCall(PetscMalloc1(newLength, &newformat)); 188 } 189 PetscCall(PetscFormatConvert(format, newformat)); 190 #if defined(PETSC_HAVE_VSNPRINTF) 191 flen = vsnprintf(str, len, newformat, Argp); 192 #else 193 #error "vsnprintf not found" 194 #endif 195 if (newLength > sizeof(formatbuf) - 1) PetscCall(PetscFree(newformat)); 196 { 197 PetscBool foundedot; 198 size_t cnt = 0, ncnt = 0, leng; 199 PetscCall(PetscStrlen(str, &leng)); 200 if (leng > 4) { 201 for (cnt = 0; cnt < leng - 4; cnt++) { 202 if (str[cnt] == '[' && str[cnt + 1] == '|') { 203 flen -= 4; 204 cnt++; 205 cnt++; 206 foundedot = PETSC_FALSE; 207 for (; cnt < leng - 1; cnt++) { 208 if (str[cnt] == '|' && str[cnt + 1] == ']') { 209 cnt++; 210 if (!foundedot) str[ncnt++] = '.'; 211 ncnt--; 212 break; 213 } else { 214 if (str[cnt] == 'e' || str[cnt] == '.') foundedot = PETSC_TRUE; 215 str[ncnt++] = str[cnt]; 216 } 217 } 218 } else { 219 str[ncnt] = str[cnt]; 220 } 221 ncnt++; 222 } 223 while (cnt < leng) { 224 str[ncnt] = str[cnt]; 225 ncnt++; 226 cnt++; 227 } 228 str[ncnt] = 0; 229 } 230 } 231 #if defined(PETSC_HAVE_WINDOWS_H) && !defined(PETSC_HAVE__SET_OUTPUT_FORMAT) 232 /* older Windows OS always produces e-+0np for floating point output; remove the extra 0 */ 233 { 234 size_t cnt = 0, ncnt = 0, leng; 235 PetscCall(PetscStrlen(str, &leng)); 236 if (leng > 5) { 237 for (cnt = 0; cnt < leng - 4; cnt++) { 238 if (str[cnt] == 'e' && (str[cnt + 1] == '-' || str[cnt + 1] == '+') && str[cnt + 2] == '0' && str[cnt + 3] >= '0' && str[cnt + 3] <= '9' && str[cnt + 4] >= '0' && str[cnt + 4] <= '9') { 239 str[ncnt] = str[cnt]; 240 ncnt++; 241 cnt++; 242 str[ncnt] = str[cnt]; 243 ncnt++; 244 cnt++; 245 cnt++; 246 str[ncnt] = str[cnt]; 247 } else { 248 str[ncnt] = str[cnt]; 249 } 250 ncnt++; 251 } 252 while (cnt < leng) { 253 str[ncnt] = str[cnt]; 254 ncnt++; 255 cnt++; 256 } 257 str[ncnt] = 0; 258 } 259 } 260 #endif 261 if (fullLength) *fullLength = 1 + (size_t)flen; 262 PetscFunctionReturn(PETSC_SUCCESS); 263 } 264 265 /*@C 266 PetscFFlush - Flush a file stream 267 268 Input Parameter: 269 . fd - The file stream handle 270 271 Level: intermediate 272 273 Notes: 274 For output streams (and for update streams on which the last operation was output), writes 275 any unwritten data from the stream's buffer to the associated output device. 276 277 For input streams (and for update streams on which the last operation was input), the 278 behavior is undefined. 279 280 If `fd` is `NULL`, all open output streams are flushed, including ones not directly 281 accessible to the program. 282 283 .seealso: `PetscPrintf()`, `PetscFPrintf()`, `PetscVFPrintf()`, `PetscVSNPrintf()` 284 @*/ 285 PetscErrorCode PetscFFlush(FILE *fd) 286 { 287 PetscFunctionBegin; 288 if (fd) PetscAssertPointer(fd, 1); 289 // could also use PetscCallExternal() here, but since we can get additional error explanation 290 // from strerror() we opted for a manual check 291 PetscCheck(0 == fflush(fd), PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE, "Error in fflush() due to \"%s\"", strerror(errno)); 292 PetscFunctionReturn(PETSC_SUCCESS); 293 } 294 295 /*@C 296 PetscVFPrintfDefault - All PETSc standard out and error messages are sent through this function; so, in theory, this can 297 can be replaced with something that does not simply write to a file. 298 299 Input Parameters: 300 + fd - the file descriptor to write to 301 . format - the format string to write with 302 - Argp - the variable argument list of items to format and write 303 304 Level: developer 305 306 Note: 307 For error messages this may be called by any MPI process, for regular standard out it is 308 called only by MPI rank 0 of a given communicator 309 310 Example Usage: 311 To use, write your own function for example, 312 .vb 313 PetscErrorCode mypetscvfprintf(FILE *fd, const char format[], va_list Argp) 314 { 315 PetscErrorCode ierr; 316 317 PetscFunctionBegin; 318 if (fd != stdout && fd != stderr) { handle regular files 319 CHKERR(PetscVFPrintfDefault(fd,format,Argp)); 320 } else { 321 char buff[BIG]; 322 size_t length; 323 PetscCall(PetscVSNPrintf(buff,BIG,format,&length,Argp)); 324 now send buff to whatever stream or whatever you want 325 } 326 PetscFunctionReturn(PETSC_SUCCESS); 327 } 328 .ve 329 then before the call to `PetscInitialize()` do the assignment `PetscVFPrintf = mypetscvfprintf`; 330 331 Developer Notes: 332 This could be called by an error handler, if that happens then a recursion of the error handler may occur 333 and a resulting crash 334 335 .seealso: `PetscVSNPrintf()`, `PetscErrorPrintf()`, `PetscFFlush()` 336 @*/ 337 PetscErrorCode PetscVFPrintfDefault(FILE *fd, const char *format, va_list Argp) 338 { 339 char str[PETSCDEFAULTBUFFERSIZE]; 340 char *buff = str; 341 size_t fullLength; 342 #if defined(PETSC_HAVE_VA_COPY) 343 va_list Argpcopy; 344 #endif 345 346 PetscFunctionBegin; 347 #if defined(PETSC_HAVE_VA_COPY) 348 va_copy(Argpcopy, Argp); 349 #endif 350 PetscCall(PetscVSNPrintf(str, sizeof(str), format, &fullLength, Argp)); 351 if (fullLength > sizeof(str)) { 352 PetscCall(PetscMalloc1(fullLength, &buff)); 353 #if defined(PETSC_HAVE_VA_COPY) 354 PetscCall(PetscVSNPrintf(buff, fullLength, format, NULL, Argpcopy)); 355 #else 356 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "C89 does not support va_copy() hence cannot print long strings with PETSc printing routines"); 357 #endif 358 } 359 #if defined(PETSC_HAVE_VA_COPY) 360 va_end(Argpcopy); 361 #endif 362 { 363 int err; 364 365 // POSIX C sets errno but otherwise it may not be set for *printf() system calls 366 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html 367 errno = 0; 368 err = fprintf(fd, "%s", buff); 369 // cannot use PetscCallExternal() for fprintf since the return value is "number of 370 // characters transmitted to the output stream" on success 371 PetscCheck(err >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE, "fprintf() returned error code %d: %s", err, errno > 0 ? strerror(errno) : "unknown (errno not set)"); 372 } 373 PetscCall(PetscFFlush(fd)); 374 if (buff != str) PetscCall(PetscFree(buff)); 375 PetscFunctionReturn(PETSC_SUCCESS); 376 } 377 378 /*@C 379 PetscSNPrintf - Prints to a string of given length 380 381 Not Collective 382 383 Input Parameters: 384 + len - the length of `str` 385 - format - the usual `printf()` format string 386 387 Output Parameter: 388 . str - the resulting string 389 390 Level: intermediate 391 392 .seealso: `PetscSynchronizedFlush()`, `PetscSynchronizedFPrintf()`, `PetscFPrintf()`, `PetscVSNPrintf()`, 393 `PetscPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, 394 `PetscVFPrintf()`, `PetscFFlush()` 395 @*/ 396 PetscErrorCode PetscSNPrintf(char *str, size_t len, const char format[], ...) 397 { 398 size_t fullLength; 399 va_list Argp; 400 401 PetscFunctionBegin; 402 va_start(Argp, format); 403 PetscCall(PetscVSNPrintf(str, len, format, &fullLength, Argp)); 404 va_end(Argp); 405 PetscFunctionReturn(PETSC_SUCCESS); 406 } 407 408 /*@C 409 PetscSNPrintfCount - Prints to a string of given length, returns count of characters printed 410 411 Not Collective 412 413 Input Parameters: 414 + len - the length of `str` 415 . format - the usual `printf()` format string 416 - ... - args to format 417 418 Output Parameters: 419 + str - the resulting string 420 - countused - number of characters printed 421 422 Level: intermediate 423 424 .seealso: `PetscSynchronizedFlush()`, `PetscSynchronizedFPrintf()`, `PetscFPrintf()`, `PetscVSNPrintf()`, 425 `PetscPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscSNPrintf()`, `PetscVFPrintf()` 426 @*/ 427 PetscErrorCode PetscSNPrintfCount(char *str, size_t len, const char format[], size_t *countused, ...) 428 { 429 va_list Argp; 430 431 PetscFunctionBegin; 432 va_start(Argp, countused); 433 PetscCall(PetscVSNPrintf(str, len, format, countused, Argp)); 434 va_end(Argp); 435 PetscFunctionReturn(PETSC_SUCCESS); 436 } 437 438 PrintfQueue petsc_printfqueue = NULL, petsc_printfqueuebase = NULL; 439 int petsc_printfqueuelength = 0; 440 441 static inline PetscErrorCode PetscVFPrintf_Private(MPI_Comm comm, FILE *fd, const char format[], va_list Argp) 442 { 443 const PetscBool tee = (PetscBool)(petsc_history && (fd != petsc_history)); 444 PetscMPIInt rank; 445 va_list cpy; 446 447 PetscFunctionBegin; 448 PetscCheck(comm != MPI_COMM_NULL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called with MPI_COMM_NULL, likely PetscObjectComm() failed"); 449 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 450 if (PetscLikely(rank != 0)) PetscFunctionReturn(PETSC_SUCCESS); 451 // must do this before we possibly consume Argp 452 if (tee) va_copy(cpy, Argp); 453 PetscCall((*PetscVFPrintf)(fd, format, Argp)); 454 if (tee) { 455 PetscCall((*PetscVFPrintf)(petsc_history, format, cpy)); 456 va_end(cpy); 457 } 458 PetscFunctionReturn(PETSC_SUCCESS); 459 } 460 461 static inline PetscErrorCode PetscSynchronizedFPrintf_Private(MPI_Comm comm, FILE *fp, const char format[], va_list Argp) 462 { 463 PetscMPIInt rank; 464 va_list cpy; 465 466 PetscFunctionBegin; 467 PetscCheck(comm != MPI_COMM_NULL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called with MPI_COMM_NULL, likely PetscObjectComm() failed"); 468 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 469 /* First processor prints immediately to fp */ 470 if (rank == 0) { 471 va_copy(cpy, Argp); 472 PetscCall(PetscVFPrintf_Private(comm, fp, format, cpy)); 473 va_end(cpy); 474 } else { /* other processors add to local queue */ 475 PrintfQueue next; 476 size_t fullLength = PETSCDEFAULTBUFFERSIZE; 477 478 PetscCall(PetscNew(&next)); 479 if (petsc_printfqueue) { 480 petsc_printfqueue->next = next; 481 petsc_printfqueue = next; 482 petsc_printfqueue->next = NULL; 483 } else petsc_printfqueuebase = petsc_printfqueue = next; 484 petsc_printfqueuelength++; 485 next->size = 0; 486 next->string = NULL; 487 while (fullLength >= next->size) { 488 next->size = fullLength + 1; 489 PetscCall(PetscFree(next->string)); 490 PetscCall(PetscMalloc1(next->size, &next->string)); 491 PetscCall(PetscArrayzero(next->string, next->size)); 492 va_copy(cpy, Argp); 493 PetscCall(PetscVSNPrintf(next->string, next->size, format, &fullLength, cpy)); 494 va_end(cpy); 495 } 496 } 497 PetscFunctionReturn(PETSC_SUCCESS); 498 } 499 500 /*@C 501 PetscSynchronizedPrintf - Prints synchronized output from multiple MPI processes. 502 Output of the first processor is followed by that of the second, etc. 503 504 Not Collective 505 506 Input Parameters: 507 + comm - the MPI communicator 508 - format - the usual `printf()` format string 509 510 Level: intermediate 511 512 Note: 513 REQUIRES a call to `PetscSynchronizedFlush()` by all the processes after the completion of the calls to `PetscSynchronizedPrintf()` for the information 514 from all the processors to be printed. 515 516 Fortran Notes: 517 The call sequence is `PetscSynchronizedPrintf`(`MPI_Comm`, `character`(*), `PetscErrorCode` ierr). 518 That is, you can only pass a single character string from Fortran. 519 520 .seealso: `PetscSynchronizedFlush()`, `PetscSynchronizedFPrintf()`, `PetscFPrintf()`, 521 `PetscPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, 522 `PetscFFlush()` 523 @*/ 524 PetscErrorCode PetscSynchronizedPrintf(MPI_Comm comm, const char format[], ...) 525 { 526 va_list Argp; 527 528 PetscFunctionBegin; 529 va_start(Argp, format); 530 PetscCall(PetscSynchronizedFPrintf_Private(comm, PETSC_STDOUT, format, Argp)); 531 va_end(Argp); 532 PetscFunctionReturn(PETSC_SUCCESS); 533 } 534 535 /*@C 536 PetscSynchronizedFPrintf - Prints synchronized output to the specified file from 537 several MPI processes. Output of the first process is followed by that of the 538 second, etc. 539 540 Not Collective 541 542 Input Parameters: 543 + comm - the MPI communicator 544 . fp - the file pointer 545 - format - the usual `printf()` format string 546 547 Level: intermediate 548 549 Note: 550 REQUIRES a intervening call to `PetscSynchronizedFlush()` for the information 551 from all the processors to be printed. 552 553 .seealso: `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`, `PetscFPrintf()`, 554 `PetscFOpen()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, 555 `PetscFFlush()` 556 @*/ 557 PetscErrorCode PetscSynchronizedFPrintf(MPI_Comm comm, FILE *fp, const char format[], ...) 558 { 559 va_list Argp; 560 561 PetscFunctionBegin; 562 va_start(Argp, format); 563 PetscCall(PetscSynchronizedFPrintf_Private(comm, fp, format, Argp)); 564 va_end(Argp); 565 PetscFunctionReturn(PETSC_SUCCESS); 566 } 567 568 /*@C 569 PetscSynchronizedFlush - Flushes to the screen output from all processors 570 involved in previous `PetscSynchronizedPrintf()`/`PetscSynchronizedFPrintf()` calls. 571 572 Collective 573 574 Input Parameters: 575 + comm - the MPI communicator 576 - fd - the file pointer (valid on MPI rank 0 of the communicator) 577 578 Level: intermediate 579 580 Note: 581 If `PetscSynchronizedPrintf()` and/or `PetscSynchronizedFPrintf()` are called with 582 different MPI communicators there must be an intervening call to `PetscSynchronizedFlush()` between the calls with different MPI communicators. 583 584 Fortran Notes: 585 Pass `PETSC_STDOUT` if the flush is for standard out; otherwise pass a value obtained from `PetscFOpen()` 586 587 .seealso: `PetscSynchronizedPrintf()`, `PetscFPrintf()`, `PetscPrintf()`, `PetscViewerASCIIPrintf()`, 588 `PetscViewerASCIISynchronizedPrintf()` 589 @*/ 590 PetscErrorCode PetscSynchronizedFlush(MPI_Comm comm, FILE *fd) 591 { 592 PetscMPIInt rank, size, tag, i, j, n = 0, dummy = 0; 593 char *message; 594 MPI_Status status; 595 596 PetscFunctionBegin; 597 PetscCall(PetscCommDuplicate(comm, &comm, &tag)); 598 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 599 PetscCallMPI(MPI_Comm_size(comm, &size)); 600 601 /* First processor waits for messages from all other processors */ 602 if (rank == 0) { 603 if (!fd) fd = PETSC_STDOUT; 604 for (i = 1; i < size; i++) { 605 /* to prevent a flood of messages to process zero, request each message separately */ 606 PetscCallMPI(MPI_Send(&dummy, 1, MPI_INT, i, tag, comm)); 607 PetscCallMPI(MPI_Recv(&n, 1, MPI_INT, i, tag, comm, &status)); 608 for (j = 0; j < n; j++) { 609 PetscMPIInt size = 0; 610 611 PetscCallMPI(MPI_Recv(&size, 1, MPI_INT, i, tag, comm, &status)); 612 PetscCall(PetscMalloc1(size, &message)); 613 PetscCallMPI(MPI_Recv(message, size, MPI_CHAR, i, tag, comm, &status)); 614 PetscCall(PetscFPrintf(comm, fd, "%s", message)); 615 PetscCall(PetscFree(message)); 616 } 617 } 618 } else { /* other processors send queue to processor 0 */ 619 PrintfQueue next = petsc_printfqueuebase, previous; 620 621 PetscCallMPI(MPI_Recv(&dummy, 1, MPI_INT, 0, tag, comm, &status)); 622 PetscCallMPI(MPI_Send(&petsc_printfqueuelength, 1, MPI_INT, 0, tag, comm)); 623 for (i = 0; i < petsc_printfqueuelength; i++) { 624 PetscCallMPI(MPI_Send(&next->size, 1, MPI_INT, 0, tag, comm)); 625 PetscCallMPI(MPI_Send(next->string, next->size, MPI_CHAR, 0, tag, comm)); 626 previous = next; 627 next = next->next; 628 PetscCall(PetscFree(previous->string)); 629 PetscCall(PetscFree(previous)); 630 } 631 petsc_printfqueue = NULL; 632 petsc_printfqueuelength = 0; 633 } 634 PetscCall(PetscCommDestroy(&comm)); 635 PetscFunctionReturn(PETSC_SUCCESS); 636 } 637 638 /*@C 639 PetscFPrintf - Prints to a file, only from the first 640 MPI process in the communicator. 641 642 Not Collective; No Fortran Support 643 644 Input Parameters: 645 + comm - the MPI communicator 646 . fd - the file pointer 647 - format - the usual `printf()` format string 648 649 Level: intermediate 650 651 Developer Notes: 652 This maybe, and is, called from PETSc error handlers and `PetscMallocValidate()` hence it does not use `PetscCallMPI()` which 653 could recursively restart the malloc validation. 654 655 .seealso: `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, 656 `PetscViewerASCIISynchronizedPrintf()`, `PetscSynchronizedFlush()`, `PetscFFlush()` 657 @*/ 658 PetscErrorCode PetscFPrintf(MPI_Comm comm, FILE *fd, const char format[], ...) 659 { 660 va_list Argp; 661 662 PetscFunctionBegin; 663 va_start(Argp, format); 664 PetscCall(PetscVFPrintf_Private(comm, fd, format, Argp)); 665 va_end(Argp); 666 PetscFunctionReturn(PETSC_SUCCESS); 667 } 668 669 /*@C 670 PetscPrintf - Prints to standard out, only from the first 671 MPI process in the communicator. Calls from other processes are ignored. 672 673 Not Collective 674 675 Input Parameters: 676 + comm - the communicator 677 - format - the usual `printf()` format string 678 679 Level: intermediate 680 681 Note: 682 Deprecated information: `PetscPrintf()` supports some format specifiers that are unique to PETSc. 683 See the manual page for `PetscFormatConvert()` for details. 684 685 Fortran Notes: 686 The call sequence is `PetscPrintf`(MPI_Comm, character(*), `PetscErrorCode` ierr) from Fortran. 687 That is, you can only pass a single character string from Fortran. 688 689 .seealso: `PetscFPrintf()`, `PetscSynchronizedPrintf()`, `PetscFormatConvert()`, `PetscFFlush()` 690 @*/ 691 PetscErrorCode PetscPrintf(MPI_Comm comm, const char format[], ...) 692 { 693 va_list Argp; 694 695 PetscFunctionBegin; 696 va_start(Argp, format); 697 PetscCall(PetscVFPrintf_Private(comm, PETSC_STDOUT, format, Argp)); 698 va_end(Argp); 699 PetscFunctionReturn(PETSC_SUCCESS); 700 } 701 702 PetscErrorCode PetscHelpPrintfDefault(MPI_Comm comm, const char format[], ...) 703 { 704 va_list Argp; 705 706 PetscFunctionBegin; 707 va_start(Argp, format); 708 PetscCall(PetscVFPrintf_Private(comm, PETSC_STDOUT, format, Argp)); 709 va_end(Argp); 710 PetscFunctionReturn(PETSC_SUCCESS); 711 } 712 713 /*@C 714 PetscSynchronizedFGets - Multiple MPI processes all get the same line from a file. 715 716 Collective 717 718 Input Parameters: 719 + comm - the MPI communicator 720 . fp - the file pointer 721 - len - the length of `string` 722 723 Output Parameter: 724 . string - the line read from the file, at end of file `string`[0] == 0 725 726 Level: intermediate 727 728 .seealso: `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`, 729 `PetscFOpen()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPrintf()` 730 @*/ 731 PetscErrorCode PetscSynchronizedFGets(MPI_Comm comm, FILE *fp, size_t len, char string[]) 732 { 733 PetscMPIInt rank; 734 735 PetscFunctionBegin; 736 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 737 if (rank == 0) { 738 if (!fgets(string, len, fp)) { 739 string[0] = 0; 740 PetscCheck(feof(fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file due to \"%s\"", strerror(errno)); 741 } 742 } 743 PetscCallMPI(MPI_Bcast(string, len, MPI_BYTE, 0, comm)); 744 PetscFunctionReturn(PETSC_SUCCESS); 745 } 746 747 PetscErrorCode PetscFormatRealArray(char buf[], size_t len, const char *fmt, PetscInt n, const PetscReal x[]) 748 { 749 PetscInt i; 750 size_t left, count; 751 char *p; 752 753 PetscFunctionBegin; 754 for (i = 0, p = buf, left = len; i < n; i++) { 755 PetscCall(PetscSNPrintfCount(p, left, fmt, &count, (double)x[i])); 756 PetscCheck(count < left, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Insufficient space in buffer"); 757 left -= count; 758 p += count - 1; 759 *p++ = ' '; 760 } 761 p[i ? 0 : -1] = 0; 762 PetscFunctionReturn(PETSC_SUCCESS); 763 } 764