xref: /petsc/src/sys/error/err.c (revision 1b37a2a7cc4a4fb30c3e967db1c694c0a1013f51)
1 /*
2       Code that allows one to set the error handlers
3       Portions of this code are under:
4       Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
5 */
6 #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/
7 #include <petscviewer.h>
8 
9 typedef struct _EH *EH;
10 struct _EH {
11   PetscErrorCode (*handler)(MPI_Comm, int, const char *, const char *, PetscErrorCode, PetscErrorType, const char *, void *);
12   void *ctx;
13   EH    previous;
14 };
15 
16 /* This is here to allow the traceback error handler (or potentially other error handlers)
17    to certify that PETSCABORT is being called on all MPI processes, and that it should be possible to call
18    MPI_Finalize() and exit().  This should only be used when `PetscCIEnabledPortabeErrorOutput == PETSC_TRUE`
19    to allow testing of error messages.  Do not rely on this for clean exit in production. */
20 PetscBool petscabortmpifinalize = PETSC_FALSE;
21 
22 static EH eh = NULL;
23 
24 /*@C
25   PetscEmacsClientErrorHandler - Error handler that uses the emacsclient program to
26   load the file where the error occurred. Then calls the "previous" error handler.
27 
28   Not Collective
29 
30   Input Parameters:
31 + comm - communicator over which error occurred
32 . line - the line number of the error (usually indicated by `__LINE__` in the calling routine)
33 . file - the file in which the error was detected (usually indicated by `__FILE__` in the calling routine)
34 . fun  - the function name of the calling routine
35 . mess - an error text string, usually just printed to the screen
36 . n    - the generic error number
37 . p    - `PETSC_ERROR_INITIAL` indicates this is the first time the error handler is being called while `PETSC_ERROR_REPEAT` indicates it was previously called
38 - ctx  - error handler context
39 
40   Options Database Key:
41 . -on_error_emacs <machinename> - will contact machinename to open the Emacs client there
42 
43   Level: developer
44 
45   Note:
46   You must put (server-start) in your .emacs file for the emacsclient software to work
47 
48   Developer Note:
49   Since this is an error handler it cannot call `PetscCall()`; thus we just return if an error is detected.
50   But some of the functions it calls do perform error checking that may not be appropriate in a error handler call.
51 
52 .seealso: `PetscError()`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscAttachDebuggerErrorHandler()`,
53           `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscTraceBackErrorHandler()`, `PetscReturnErrorHandler()`,
54           `PetscErrorType`, `PETSC_ERROR_INITIAL`, `PETSC_ERROR_REPEAT`, `PetscErrorCode`
55  @*/
56 PetscErrorCode PetscEmacsClientErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx)
57 {
58   PetscErrorCode ierr;
59   char           command[PETSC_MAX_PATH_LEN];
60   const char    *pdir;
61   FILE          *fp;
62 
63   ierr = PetscGetPetscDir(&pdir);
64   if (ierr) return ierr;
65   ierr = PetscSNPrintf(command, PETSC_STATIC_ARRAY_LENGTH(command), "cd %s; emacsclient --no-wait +%d %s\n", pdir, line, file);
66   if (ierr) return ierr;
67 #if defined(PETSC_HAVE_POPEN)
68   ierr = PetscPOpen(MPI_COMM_WORLD, (char *)ctx, command, "r", &fp);
69   if (ierr) return ierr;
70   ierr = PetscPClose(MPI_COMM_WORLD, fp);
71   if (ierr) return ierr;
72 #else
73   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
74 #endif
75   ierr = PetscPopErrorHandler();
76   if (ierr) return ierr; /* remove this handler from the stack of handlers */
77   if (!eh) {
78     ierr = PetscTraceBackErrorHandler(comm, line, fun, file, n, p, mess, NULL);
79     if (ierr) return ierr;
80   } else {
81     ierr = (*eh->handler)(comm, line, fun, file, n, p, mess, eh->ctx);
82     if (ierr) return ierr;
83   }
84   return PETSC_SUCCESS;
85 }
86 
87 /*@C
88   PetscPushErrorHandler - Sets a routine to be called on detection of errors.
89 
90   Not Collective
91 
92   Input Parameters:
93 + handler - error handler routine
94 - ctx     - optional handler context that contains information needed by the handler (for
95             example file pointers for error messages etc.)
96 
97   Calling sequence of `handler`:
98 + comm - communicator over which error occurred
99 . line - the line number of the error (usually indicated by `__LINE__` in the calling routine)
100 . file - the file in which the error was detected (usually indicated by `__FILE__` in the calling routine)
101 . fun  - the function name of the calling routine
102 . n    - the generic error number (see list defined in include/petscerror.h)
103 . p    - `PETSC_ERROR_INITIAL` if error just detected, otherwise `PETSC_ERROR_REPEAT`
104 . mess - an error text string, usually just printed to the screen
105 - ctx  - the error handler context
106 
107   Options Database Keys:
108 + -on_error_attach_debugger <noxterm,lldb or gdb> - starts up the debugger if an error occurs
109 - -on_error_abort                                 - aborts the program if an error occurs
110 
111   Level: intermediate
112 
113   Note:
114   The currently available PETSc error handlers include `PetscTraceBackErrorHandler()`,
115   `PetscAttachDebuggerErrorHandler()`, `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, and `PetscReturnErrorHandler()`.
116 
117   Fortran Note:
118   You can only push a single error handler from Fortran before popping it.
119 
120 .seealso: `PetscPopErrorHandler()`, `PetscAttachDebuggerErrorHandler()`, `PetscAbortErrorHandler()`, `PetscTraceBackErrorHandler()`, `PetscPushSignalHandler()`,
121           `PetscErrorType`, `PETSC_ERROR_INITIAL`, `PETSC_ERROR_REPEAT`, `PetscErrorCode`
122 @*/
123 PetscErrorCode PetscPushErrorHandler(PetscErrorCode (*handler)(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx), void *ctx)
124 {
125   EH neweh;
126 
127   PetscFunctionBegin;
128   PetscCall(PetscNew(&neweh));
129   if (eh) neweh->previous = eh;
130   else neweh->previous = NULL;
131   neweh->handler = handler;
132   neweh->ctx     = ctx;
133   eh             = neweh;
134   PetscFunctionReturn(PETSC_SUCCESS);
135 }
136 
137 /*@
138   PetscPopErrorHandler - Removes the latest error handler that was
139   pushed with `PetscPushErrorHandler()`.
140 
141   Not Collective
142 
143   Level: intermediate
144 
145 .seealso: `PetscPushErrorHandler()`
146 @*/
147 PetscErrorCode PetscPopErrorHandler(void)
148 {
149   EH tmp;
150 
151   PetscFunctionBegin;
152   if (!eh) PetscFunctionReturn(PETSC_SUCCESS);
153   tmp = eh;
154   eh  = eh->previous;
155   PetscCall(PetscFree(tmp));
156   PetscFunctionReturn(PETSC_SUCCESS);
157 }
158 
159 /*@C
160   PetscReturnErrorHandler - Error handler that causes a return without printing an error message.
161 
162   Not Collective
163 
164   Input Parameters:
165 + comm - communicator over which error occurred
166 . line - the line number of the error (usually indicated by `__LINE__` in the calling routine)
167 . fun  - the function name
168 . file - the file in which the error was detected (usually indicated by `__FILE__` in the calling routine)
169 . mess - an error text string, usually just printed to the screen
170 . n    - the generic error number
171 . p    - `PETSC_ERROR_INITIAL` indicates this is the first time the error handler is being called while `PETSC_ERROR_REPEAT` indicates it was previously called
172 - ctx  - error handler context
173 
174   Level: developer
175 
176   Notes:
177   Users do not directly employ this routine
178 
179   Use `PetscPushErrorHandler()` to set the desired error handler.  The
180   currently available PETSc error handlers include `PetscTraceBackErrorHandler()`,
181   `PetscAttachDebuggerErrorHandler()`, and `PetscAbortErrorHandler()`.
182 
183 .seealso: `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscError()`, `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscTraceBackErrorHandler()`,
184           `PetscAttachDebuggerErrorHandler()`, `PetscEmacsClientErrorHandler()`,
185           `PetscErrorType`, `PETSC_ERROR_INITIAL`, `PETSC_ERROR_REPEAT`, `PetscErrorCode`
186  @*/
187 PetscErrorCode PetscReturnErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx)
188 {
189   (void)comm;
190   (void)line;
191   (void)fun;
192   (void)file;
193   (void)p;
194   (void)mess;
195   (void)ctx;
196   return n;
197 }
198 
199 static char PetscErrorBaseMessage[1024];
200 /*
201        The numerical values for these are defined in include/petscerror.h; any changes
202    there must also be made here
203 */
204 static const char *PetscErrorStrings[] = {
205   /*55 */ "Out of memory",
206   "No support for this operation for this object type",
207   "No support for this operation on this system",
208   /*58 */ "Operation done in wrong order",
209   /*59 */ "Signal received",
210   /*60 */ "Nonconforming object sizes",
211   "Argument aliasing not permitted",
212   "Invalid argument",
213   /*63 */ "Argument out of range",
214   "Corrupt argument: https://petsc.org/release/faq/#valgrind",
215   "Unable to open file",
216   "Read from file failed",
217   "Write to file failed",
218   "Invalid pointer",
219   /*69 */ "Arguments must have same type",
220   /*70 */ "Attempt to use a pointer that does not point to a valid accessible location",
221   /*71 */ "Zero pivot in LU factorization: https://petsc.org/release/faq/#zeropivot",
222   /*72 */ "Floating point exception",
223   /*73 */ "Object is in wrong state",
224   "Corrupted Petsc object",
225   "Arguments are incompatible",
226   "Error in external library",
227   /*77 */ "Petsc has generated inconsistent data",
228   "Memory corruption: https://petsc.org/release/faq/#valgrind",
229   "Unexpected data in file",
230   /*80 */ "Arguments must have same communicators",
231   /*81 */ "Zero pivot in Cholesky factorization: https://petsc.org/release/faq/#zeropivot",
232   "",
233   "",
234   "Overflow in integer operation: https://petsc.org/release/faq/#64-bit-indices",
235   /*85 */ "Null argument, when expecting valid pointer",
236   /*86 */ "Unknown type. Check for miss-spelling or missing package: https://petsc.org/release/install/install/#external-packages",
237   /*87 */ "MPI library at runtime is not compatible with MPI used at compile time",
238   /*88 */ "Error in system call",
239   /*89 */ "Object Type not set: https://petsc.org/release/faq/#object-type-not-set",
240   /*90 */ "",
241   /*   */ "",
242   /*92 */ "See https://petsc.org/release/overview/linear_solve_table/ for possible LU and Cholesky solvers",
243   /*93 */ "You cannot overwrite this option since that will conflict with other previously set options",
244   /*94 */ "Example/application run with number of MPI ranks it does not support",
245   /*95 */ "Missing or incorrect user input",
246   /*96 */ "GPU resources unavailable",
247   /*97 */ "GPU error",
248   /*98 */ "General MPI error",
249   /*99 */ "PetscError() incorrectly returned an error code of 0"};
250 
251 /*@C
252   PetscErrorMessage - Returns the text string associated with a PETSc error code.
253 
254   Not Collective
255 
256   Input Parameter:
257 . errnum - the error code
258 
259   Output Parameters:
260 + text     - the error message (`NULL` if not desired)
261 - specific - the specific error message that was set with `SETERRQ()` or
262              `PetscError()`. (`NULL` if not desired)
263 
264   Level: developer
265 
266 .seealso: `PetscErrorCode`, `PetscPushErrorHandler()`, `PetscAttachDebuggerErrorHandler()`,
267 `PetscError()`, `SETERRQ()`, `PetscCall()` `PetscAbortErrorHandler()`,
268 `PetscTraceBackErrorHandler()`
269 @*/
270 PetscErrorCode PetscErrorMessage(PetscErrorCode errnum, const char *text[], char **specific)
271 {
272   PetscFunctionBegin;
273   if (text) {
274     if (errnum > PETSC_ERR_MIN_VALUE && errnum < PETSC_ERR_MAX_VALUE) {
275       size_t len;
276 
277       *text = PetscErrorStrings[errnum - PETSC_ERR_MIN_VALUE - 1];
278       PetscCall(PetscStrlen(*text, &len));
279       if (!len) *text = NULL;
280     } else if (errnum == PETSC_ERR_BOOLEAN_MACRO_FAILURE) {
281       /* this "error code" arises from failures in boolean macros, where the || operator is
282          used to short-circuit the macro call in case of error. This has the side effect of
283          "returning" either 0 (PETSC_SUCCESS) or 1 (PETSC_ERR_UNKNONWN):
284 
285          #define PETSC_FOO(x) ((PetscErrorCode)(PetscBar(x) || PetscBaz(x)))
286 
287          If PetscBar() fails (returns nonzero) PetscBaz() is not executed but the result of
288          this expression is boolean false, hence PETSC_ERR_UNNOWN
289        */
290       *text = "Error occurred in boolean shortcuit in macro";
291     } else {
292       *text = NULL;
293     }
294   }
295   if (specific) *specific = PetscErrorBaseMessage;
296   PetscFunctionReturn(PETSC_SUCCESS);
297 }
298 
299 #if defined(PETSC_CLANGUAGE_CXX)
300   /* C++ exceptions are formally not allowed to propagate through extern "C" code. In practice, far too much software
301  * would be broken if implementations did not handle it it some common cases. However, keep in mind
302  *
303  *   Rule 62. Don't allow exceptions to propagate across module boundaries
304  *
305  * in "C++ Coding Standards" by Sutter and Alexandrescu. (This accounts for part of the ongoing C++ binary interface
306  * instability.) Having PETSc raise errors as C++ exceptions was probably misguided and should eventually be removed.
307  *
308  * Here is the problem: You have a C++ function call a PETSc function, and you would like to maintain the error message
309  * and stack information from the PETSc error. You could make everyone write exactly this code in their C++, but that
310  * seems crazy to me.
311  */
312   #include <sstream>
313   #include <stdexcept>
314 static void PetscCxxErrorThrow()
315 {
316   const char *str;
317   if (eh && eh->ctx) {
318     std::ostringstream *msg;
319     msg = (std::ostringstream *)eh->ctx;
320     str = msg->str().c_str();
321   } else str = "Error detected in C PETSc";
322 
323   throw std::runtime_error(str);
324 }
325 #endif
326 
327 /*@C
328   PetscError - Routine that is called when an error has been detected, usually called through the macro `SETERRQ`(`PETSC_COMM_SELF`,)` or by `PetscCall()`.
329 
330   Collective
331 
332   Input Parameters:
333 + comm - communicator over which error occurred.  ALL MPI processes of this communicator MUST call this routine
334 . line - the line number of the error (usually indicated by `__LINE__` in the calling routine)
335 . func - the function name in which the error was detected
336 . file - the file in which the error was detected (usually indicated by `__FILE__` in the calling routine)
337 . n    - the generic error number
338 . p    - `PETSC_ERROR_INITIAL` indicates the error was initially detected, `PETSC_ERROR_REPEAT` indicates this is a traceback from a previously detected error
339 - mess - formatted message string - aka printf
340 
341   Options Database Keys:
342 + -error_output_stdout - output the error messages to `stdout` instead of the default `stderr`
343 - -error_output_none   - do not output the error messages
344 
345   Level: intermediate
346 
347   Notes:
348   PETSc error handling is done with error return codes. A non-zero return indicates an error
349   was detected. The return-value of this routine is what is ultimately returned by
350   `SETERRQ()`.
351 
352   Numerical errors (potential divide by zero, for example) are not managed by the
353   error return codes; they are managed via, for example, `KSPGetConvergedReason()` that
354   indicates if the solve was successful or not. The option `-ksp_error_if_not_converged`, for
355   example, turns numerical failures into hard errors managed via `PetscError()`.
356 
357   PETSc provides a rich supply of error handlers, see the list below, and users can also
358   provide their own error handlers.
359 
360   If the user sets their own error handler (via `PetscPushErrorHandler()`) they may return any
361   arbitrary value from it, but are encouraged to return nonzero values. If the return value is
362   zero, `SETERRQ()` will ignore the value and return `PETSC_ERR_RETURN` (a nonzero value)
363   instead.
364 
365   Most users need not directly use this routine and the error handlers, but can instead use
366   the simplified interface `PetscCall()` or `SETERRQ()`.
367 
368   Fortran Note:
369   This routine is used differently from Fortran
370 .vb
371   PetscError(MPI_Comm comm, PetscErrorCode n, PetscErrorType p, char *message)
372 .ve
373 
374   Developer Note:
375   Since this is called after an error condition it should not be calling any error handlers (currently it ignores any error codes)
376   BUT this routine does call regular PETSc functions that may call error handlers, this is problematic and could be fixed by never calling other PETSc routines
377   but this annoying.
378 
379 .seealso: `PetscErrorCode`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscTraceBackErrorHandler()`, `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`,
380           `PetscReturnErrorHandler()`, `PetscAttachDebuggerErrorHandler()`, `PetscEmacsClientErrorHandler()`,
381           `SETERRQ()`, `PetscCall()`, `CHKMEMQ`, `PetscErrorMessage()`, `PETSCABORT()`, `PetscErrorType`, `PETSC_ERROR_INITIAL`, `PETSC_ERROR_REPEAT`
382 @*/
383 PetscErrorCode PetscError(MPI_Comm comm, int line, const char *func, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, ...)
384 {
385   va_list        Argp;
386   size_t         fullLength;
387   char           buf[2048], *lbuf = NULL;
388   PetscBool      ismain;
389   PetscErrorCode ierr;
390 
391   if (!PetscErrorHandlingInitialized) return n;
392   if (comm == MPI_COMM_NULL) comm = PETSC_COMM_SELF;
393 
394   /* Compose the message evaluating the print format */
395   if (mess) {
396     va_start(Argp, mess);
397     ierr = PetscVSNPrintf(buf, 2048, mess, &fullLength, Argp);
398     va_end(Argp);
399     lbuf = buf;
400     if (p == PETSC_ERROR_INITIAL) ierr = PetscStrncpy(PetscErrorBaseMessage, lbuf, sizeof(PetscErrorBaseMessage));
401   }
402 
403   if (p == PETSC_ERROR_INITIAL && n != PETSC_ERR_MEMC) ierr = PetscMallocValidate(__LINE__, PETSC_FUNCTION_NAME, __FILE__);
404 
405   if (!eh) ierr = PetscTraceBackErrorHandler(comm, line, func, file, n, p, lbuf, NULL);
406   else ierr = (*eh->handler)(comm, line, func, file, n, p, lbuf, eh->ctx);
407   PetscStackClearTop;
408 
409   /*
410       If this is called from the main() routine we abort the program.
411       We cannot just return because them some MPI processes may continue to attempt to run
412       while this process simply exits.
413   */
414   if (func) {
415     PetscErrorCode cmp_ierr = PetscStrncmp(func, "main", 4, &ismain);
416     if (ismain) {
417       if (petscwaitonerrorflg) cmp_ierr = PetscSleep(1000);
418       (void)cmp_ierr;
419       PETSCABORT(comm, ierr);
420     }
421   }
422 #if defined(PETSC_CLANGUAGE_CXX)
423   if (p == PETSC_ERROR_IN_CXX) PetscCxxErrorThrow();
424 #endif
425   return ierr;
426 }
427 
428 /*@C
429   PetscIntView - Prints an array of integers; useful for debugging.
430 
431   Collective
432 
433   Input Parameters:
434 + N      - number of integers in array
435 . idx    - array of integers
436 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
437 
438   Level: intermediate
439 
440   Note:
441   This may be called from within the debugger
442 
443   Developer Note:
444   `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done
445 
446 .seealso: `PetscViewer`, `PetscRealView()`
447 @*/
448 PetscErrorCode PetscIntView(PetscInt N, const PetscInt idx[], PetscViewer viewer)
449 {
450   PetscMPIInt rank, size;
451   PetscInt    j, i, n = N / 20, p = N % 20;
452   PetscBool   iascii, isbinary;
453   MPI_Comm    comm;
454 
455   PetscFunctionBegin;
456   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
457   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 3);
458   if (N) PetscAssertPointer(idx, 2);
459   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
460   PetscCallMPI(MPI_Comm_size(comm, &size));
461   PetscCallMPI(MPI_Comm_rank(comm, &rank));
462 
463   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
464   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
465   if (iascii) {
466     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
467     for (i = 0; i < n; i++) {
468       if (size > 1) {
469         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":", rank, 20 * i));
470       } else {
471         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":", 20 * i));
472       }
473       for (j = 0; j < 20; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, idx[i * 20 + j]));
474       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
475     }
476     if (p) {
477       if (size > 1) {
478         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":", rank, 20 * n));
479       } else {
480         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":", 20 * n));
481       }
482       for (i = 0; i < p; i++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, idx[20 * n + i]));
483       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
484     }
485     PetscCall(PetscViewerFlush(viewer));
486     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
487   } else if (isbinary) {
488     PetscMPIInt *sizes, Ntotal, *displs, NN;
489     PetscInt    *array;
490 
491     PetscCall(PetscMPIIntCast(N, &NN));
492 
493     if (size > 1) {
494       if (rank) {
495         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm));
496         PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_INT, NULL, NULL, NULL, MPIU_INT, 0, comm));
497       } else {
498         PetscCall(PetscMalloc1(size, &sizes));
499         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm));
500         Ntotal = sizes[0];
501         PetscCall(PetscMalloc1(size, &displs));
502         displs[0] = 0;
503         for (i = 1; i < size; i++) {
504           Ntotal += sizes[i];
505           displs[i] = displs[i - 1] + sizes[i - 1];
506         }
507         PetscCall(PetscMalloc1(Ntotal, &array));
508         PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_INT, array, sizes, displs, MPIU_INT, 0, comm));
509         PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_INT));
510         PetscCall(PetscFree(sizes));
511         PetscCall(PetscFree(displs));
512         PetscCall(PetscFree(array));
513       }
514     } else {
515       PetscCall(PetscViewerBinaryWrite(viewer, idx, N, PETSC_INT));
516     }
517   } else {
518     const char *tname;
519     PetscCall(PetscObjectGetName((PetscObject)viewer, &tname));
520     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname);
521   }
522   PetscFunctionReturn(PETSC_SUCCESS);
523 }
524 
525 /*@C
526   PetscRealView - Prints an array of doubles; useful for debugging.
527 
528   Collective
529 
530   Input Parameters:
531 + N      - number of `PetscReal` in array
532 . idx    - array of `PetscReal`
533 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
534 
535   Level: intermediate
536 
537   Note:
538   This may be called from within the debugger
539 
540   Developer Note:
541   `idx` cannot be const because may be passed to binary viewer where temporary byte swapping may be done
542 
543 .seealso: `PetscViewer`, `PetscIntView()`
544 @*/
545 PetscErrorCode PetscRealView(PetscInt N, const PetscReal idx[], PetscViewer viewer)
546 {
547   PetscMPIInt rank, size;
548   PetscInt    j, i, n = N / 5, p = N % 5;
549   PetscBool   iascii, isbinary;
550   MPI_Comm    comm;
551 
552   PetscFunctionBegin;
553   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
554   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 3);
555   PetscAssertPointer(idx, 2);
556   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
557   PetscCallMPI(MPI_Comm_size(comm, &size));
558   PetscCallMPI(MPI_Comm_rank(comm, &rank));
559 
560   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
561   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
562   if (iascii) {
563     PetscInt tab;
564 
565     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
566     PetscCall(PetscViewerASCIIGetTab(viewer, &tab));
567     for (i = 0; i < n; i++) {
568       PetscCall(PetscViewerASCIISetTab(viewer, tab));
569       if (size > 1) {
570         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 5 * i));
571       } else {
572         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 5 * i));
573       }
574       PetscCall(PetscViewerASCIISetTab(viewer, 0));
575       for (j = 0; j < 5; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[i * 5 + j]));
576       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
577     }
578     if (p) {
579       PetscCall(PetscViewerASCIISetTab(viewer, tab));
580       if (size > 1) {
581         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 5 * n));
582       } else {
583         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 5 * n));
584       }
585       PetscCall(PetscViewerASCIISetTab(viewer, 0));
586       for (i = 0; i < p; i++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[5 * n + i]));
587       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
588     }
589     PetscCall(PetscViewerFlush(viewer));
590     PetscCall(PetscViewerASCIISetTab(viewer, tab));
591     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
592   } else if (isbinary) {
593     PetscMPIInt *sizes, *displs, Ntotal, NN;
594     PetscReal   *array;
595 
596     PetscCall(PetscMPIIntCast(N, &NN));
597 
598     if (size > 1) {
599       if (rank) {
600         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm));
601         PetscCallMPI(MPI_Gatherv((PetscReal *)idx, NN, MPIU_REAL, NULL, NULL, NULL, MPIU_REAL, 0, comm));
602       } else {
603         PetscCall(PetscMalloc1(size, &sizes));
604         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm));
605         Ntotal = sizes[0];
606         PetscCall(PetscMalloc1(size, &displs));
607         displs[0] = 0;
608         for (i = 1; i < size; i++) {
609           Ntotal += sizes[i];
610           displs[i] = displs[i - 1] + sizes[i - 1];
611         }
612         PetscCall(PetscMalloc1(Ntotal, &array));
613         PetscCallMPI(MPI_Gatherv((PetscReal *)idx, NN, MPIU_REAL, array, sizes, displs, MPIU_REAL, 0, comm));
614         PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_REAL));
615         PetscCall(PetscFree(sizes));
616         PetscCall(PetscFree(displs));
617         PetscCall(PetscFree(array));
618       }
619     } else {
620       PetscCall(PetscViewerBinaryWrite(viewer, (void *)idx, N, PETSC_REAL));
621     }
622   } else {
623     const char *tname;
624     PetscCall(PetscObjectGetName((PetscObject)viewer, &tname));
625     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname);
626   }
627   PetscFunctionReturn(PETSC_SUCCESS);
628 }
629 
630 /*@C
631   PetscScalarView - Prints an array of `PetscScalar`; useful for debugging.
632 
633   Collective
634 
635   Input Parameters:
636 + N      - number of scalars in array
637 . idx    - array of scalars
638 - viewer - location to print array, `PETSC_VIEWER_STDOUT_WORLD`, `PETSC_VIEWER_STDOUT_SELF` or 0
639 
640   Level: intermediate
641 
642   Note:
643   This may be called from within the debugger
644 
645   Developer Note:
646   `idx` cannot be const because may be passed to binary viewer where byte swapping may be done
647 
648 .seealso: `PetscViewer`, `PetscIntView()`, `PetscRealView()`
649 @*/
650 PetscErrorCode PetscScalarView(PetscInt N, const PetscScalar idx[], PetscViewer viewer)
651 {
652   PetscMPIInt rank, size;
653   PetscInt    j, i, n = N / 3, p = N % 3;
654   PetscBool   iascii, isbinary;
655   MPI_Comm    comm;
656 
657   PetscFunctionBegin;
658   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
659   PetscValidHeader(viewer, 3);
660   if (N) PetscAssertPointer(idx, 2);
661   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
662   PetscCallMPI(MPI_Comm_size(comm, &size));
663   PetscCallMPI(MPI_Comm_rank(comm, &rank));
664 
665   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
666   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
667   if (iascii) {
668     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
669     for (i = 0; i < n; i++) {
670       if (size > 1) {
671         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 3 * i));
672       } else {
673         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 3 * i));
674       }
675       for (j = 0; j < 3; j++) {
676 #if defined(PETSC_USE_COMPLEX)
677         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%12.4e,%12.4e)", (double)PetscRealPart(idx[i * 3 + j]), (double)PetscImaginaryPart(idx[i * 3 + j])));
678 #else
679         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[i * 3 + j]));
680 #endif
681       }
682       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
683     }
684     if (p) {
685       if (size > 1) {
686         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %2" PetscInt_FMT ":", rank, 3 * n));
687       } else {
688         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%2" PetscInt_FMT ":", 3 * n));
689       }
690       for (i = 0; i < p; i++) {
691 #if defined(PETSC_USE_COMPLEX)
692         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%12.4e,%12.4e)", (double)PetscRealPart(idx[n * 3 + i]), (double)PetscImaginaryPart(idx[n * 3 + i])));
693 #else
694         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %12.4e", (double)idx[3 * n + i]));
695 #endif
696       }
697       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
698     }
699     PetscCall(PetscViewerFlush(viewer));
700     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
701   } else if (isbinary) {
702     PetscMPIInt *sizes, Ntotal, *displs, NN;
703     PetscScalar *array;
704 
705     PetscCall(PetscMPIIntCast(N, &NN));
706 
707     if (size > 1) {
708       if (rank) {
709         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm));
710         PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_SCALAR, NULL, NULL, NULL, MPIU_SCALAR, 0, comm));
711       } else {
712         PetscCall(PetscMalloc1(size, &sizes));
713         PetscCallMPI(MPI_Gather(&NN, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm));
714         Ntotal = sizes[0];
715         PetscCall(PetscMalloc1(size, &displs));
716         displs[0] = 0;
717         for (i = 1; i < size; i++) {
718           Ntotal += sizes[i];
719           displs[i] = displs[i - 1] + sizes[i - 1];
720         }
721         PetscCall(PetscMalloc1(Ntotal, &array));
722         PetscCallMPI(MPI_Gatherv((void *)idx, NN, MPIU_SCALAR, array, sizes, displs, MPIU_SCALAR, 0, comm));
723         PetscCall(PetscViewerBinaryWrite(viewer, array, Ntotal, PETSC_SCALAR));
724         PetscCall(PetscFree(sizes));
725         PetscCall(PetscFree(displs));
726         PetscCall(PetscFree(array));
727       }
728     } else {
729       PetscCall(PetscViewerBinaryWrite(viewer, (void *)idx, N, PETSC_SCALAR));
730     }
731   } else {
732     const char *tname;
733     PetscCall(PetscObjectGetName((PetscObject)viewer, &tname));
734     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle that PetscViewer of type %s", tname);
735   }
736   PetscFunctionReturn(PETSC_SUCCESS);
737 }
738 
739 #if defined(PETSC_HAVE_CUDA)
740   #include <petscdevice_cuda.h>
741 PETSC_EXTERN const char *PetscCUBLASGetErrorName(cublasStatus_t status)
742 {
743   switch (status) {
744   #if (CUDART_VERSION >= 8000) /* At least CUDA 8.0 of Sep. 2016 had these */
745   case CUBLAS_STATUS_SUCCESS:
746     return "CUBLAS_STATUS_SUCCESS";
747   case CUBLAS_STATUS_NOT_INITIALIZED:
748     return "CUBLAS_STATUS_NOT_INITIALIZED";
749   case CUBLAS_STATUS_ALLOC_FAILED:
750     return "CUBLAS_STATUS_ALLOC_FAILED";
751   case CUBLAS_STATUS_INVALID_VALUE:
752     return "CUBLAS_STATUS_INVALID_VALUE";
753   case CUBLAS_STATUS_ARCH_MISMATCH:
754     return "CUBLAS_STATUS_ARCH_MISMATCH";
755   case CUBLAS_STATUS_MAPPING_ERROR:
756     return "CUBLAS_STATUS_MAPPING_ERROR";
757   case CUBLAS_STATUS_EXECUTION_FAILED:
758     return "CUBLAS_STATUS_EXECUTION_FAILED";
759   case CUBLAS_STATUS_INTERNAL_ERROR:
760     return "CUBLAS_STATUS_INTERNAL_ERROR";
761   case CUBLAS_STATUS_NOT_SUPPORTED:
762     return "CUBLAS_STATUS_NOT_SUPPORTED";
763   case CUBLAS_STATUS_LICENSE_ERROR:
764     return "CUBLAS_STATUS_LICENSE_ERROR";
765   #endif
766   default:
767     return "unknown error";
768   }
769 }
770 PETSC_EXTERN const char *PetscCUSolverGetErrorName(cusolverStatus_t status)
771 {
772   switch (status) {
773   #if (CUDART_VERSION >= 8000) /* At least CUDA 8.0 of Sep. 2016 had these */
774   case CUSOLVER_STATUS_SUCCESS:
775     return "CUSOLVER_STATUS_SUCCESS";
776   case CUSOLVER_STATUS_NOT_INITIALIZED:
777     return "CUSOLVER_STATUS_NOT_INITIALIZED";
778   case CUSOLVER_STATUS_INVALID_VALUE:
779     return "CUSOLVER_STATUS_INVALID_VALUE";
780   case CUSOLVER_STATUS_ARCH_MISMATCH:
781     return "CUSOLVER_STATUS_ARCH_MISMATCH";
782   case CUSOLVER_STATUS_INTERNAL_ERROR:
783     return "CUSOLVER_STATUS_INTERNAL_ERROR";
784     #if (CUDART_VERSION >= 9000) /* CUDA 9.0 had these defined on June 2021 */
785   case CUSOLVER_STATUS_ALLOC_FAILED:
786     return "CUSOLVER_STATUS_ALLOC_FAILED";
787   case CUSOLVER_STATUS_MAPPING_ERROR:
788     return "CUSOLVER_STATUS_MAPPING_ERROR";
789   case CUSOLVER_STATUS_EXECUTION_FAILED:
790     return "CUSOLVER_STATUS_EXECUTION_FAILED";
791   case CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
792     return "CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED";
793   case CUSOLVER_STATUS_NOT_SUPPORTED:
794     return "CUSOLVER_STATUS_NOT_SUPPORTED ";
795   case CUSOLVER_STATUS_ZERO_PIVOT:
796     return "CUSOLVER_STATUS_ZERO_PIVOT";
797   case CUSOLVER_STATUS_INVALID_LICENSE:
798     return "CUSOLVER_STATUS_INVALID_LICENSE";
799     #endif
800   #endif
801   default:
802     return "unknown error";
803   }
804 }
805 PETSC_EXTERN const char *PetscCUFFTGetErrorName(cufftResult result)
806 {
807   switch (result) {
808   case CUFFT_SUCCESS:
809     return "CUFFT_SUCCESS";
810   case CUFFT_INVALID_PLAN:
811     return "CUFFT_INVALID_PLAN";
812   case CUFFT_ALLOC_FAILED:
813     return "CUFFT_ALLOC_FAILED";
814   case CUFFT_INVALID_TYPE:
815     return "CUFFT_INVALID_TYPE";
816   case CUFFT_INVALID_VALUE:
817     return "CUFFT_INVALID_VALUE";
818   case CUFFT_INTERNAL_ERROR:
819     return "CUFFT_INTERNAL_ERROR";
820   case CUFFT_EXEC_FAILED:
821     return "CUFFT_EXEC_FAILED";
822   case CUFFT_SETUP_FAILED:
823     return "CUFFT_SETUP_FAILED";
824   case CUFFT_INVALID_SIZE:
825     return "CUFFT_INVALID_SIZE";
826   case CUFFT_UNALIGNED_DATA:
827     return "CUFFT_UNALIGNED_DATA";
828   case CUFFT_INCOMPLETE_PARAMETER_LIST:
829     return "CUFFT_INCOMPLETE_PARAMETER_LIST";
830   case CUFFT_INVALID_DEVICE:
831     return "CUFFT_INVALID_DEVICE";
832   case CUFFT_PARSE_ERROR:
833     return "CUFFT_PARSE_ERROR";
834   case CUFFT_NO_WORKSPACE:
835     return "CUFFT_NO_WORKSPACE";
836   case CUFFT_NOT_IMPLEMENTED:
837     return "CUFFT_NOT_IMPLEMENTED";
838   case CUFFT_LICENSE_ERROR:
839     return "CUFFT_LICENSE_ERROR";
840   case CUFFT_NOT_SUPPORTED:
841     return "CUFFT_NOT_SUPPORTED";
842   default:
843     return "unknown error";
844   }
845 }
846 #endif
847 
848 #if defined(PETSC_HAVE_HIP)
849   #include <petscdevice_hip.h>
850 PETSC_EXTERN const char *PetscHIPBLASGetErrorName(hipblasStatus_t status)
851 {
852   switch (status) {
853   case HIPBLAS_STATUS_SUCCESS:
854     return "HIPBLAS_STATUS_SUCCESS";
855   case HIPBLAS_STATUS_NOT_INITIALIZED:
856     return "HIPBLAS_STATUS_NOT_INITIALIZED";
857   case HIPBLAS_STATUS_ALLOC_FAILED:
858     return "HIPBLAS_STATUS_ALLOC_FAILED";
859   case HIPBLAS_STATUS_INVALID_VALUE:
860     return "HIPBLAS_STATUS_INVALID_VALUE";
861   case HIPBLAS_STATUS_ARCH_MISMATCH:
862     return "HIPBLAS_STATUS_ARCH_MISMATCH";
863   case HIPBLAS_STATUS_MAPPING_ERROR:
864     return "HIPBLAS_STATUS_MAPPING_ERROR";
865   case HIPBLAS_STATUS_EXECUTION_FAILED:
866     return "HIPBLAS_STATUS_EXECUTION_FAILED";
867   case HIPBLAS_STATUS_INTERNAL_ERROR:
868     return "HIPBLAS_STATUS_INTERNAL_ERROR";
869   case HIPBLAS_STATUS_NOT_SUPPORTED:
870     return "HIPBLAS_STATUS_NOT_SUPPORTED";
871   default:
872     return "unknown error";
873   }
874 }
875 PETSC_EXTERN const char *PetscHIPSPARSEGetErrorName(hipsparseStatus_t status)
876 {
877   switch (status) {
878   case HIPSPARSE_STATUS_SUCCESS:
879     return "HIPSPARSE_STATUS_SUCCESS";
880   case HIPSPARSE_STATUS_NOT_INITIALIZED:
881     return "HIPSPARSE_STATUS_NOT_INITIALIZED";
882   case HIPSPARSE_STATUS_ALLOC_FAILED:
883     return "HIPSPARSE_STATUS_ALLOC_FAILED";
884   case HIPSPARSE_STATUS_INVALID_VALUE:
885     return "HIPSPARSE_STATUS_INVALID_VALUE";
886   case HIPSPARSE_STATUS_ARCH_MISMATCH:
887     return "HIPSPARSE_STATUS_ARCH_MISMATCH";
888   case HIPSPARSE_STATUS_MAPPING_ERROR:
889     return "HIPSPARSE_STATUS_MAPPING_ERROR";
890   case HIPSPARSE_STATUS_EXECUTION_FAILED:
891     return "HIPSPARSE_STATUS_EXECUTION_FAILED";
892   case HIPSPARSE_STATUS_INTERNAL_ERROR:
893     return "HIPSPARSE_STATUS_INTERNAL_ERROR";
894   case HIPSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
895     return "HIPSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED";
896   case HIPSPARSE_STATUS_ZERO_PIVOT:
897     return "HIPSPARSE_STATUS_ZERO_PIVOT";
898   case HIPSPARSE_STATUS_NOT_SUPPORTED:
899     return "HIPSPARSE_STATUS_NOT_SUPPORTED";
900   case HIPSPARSE_STATUS_INSUFFICIENT_RESOURCES:
901     return "HIPSPARSE_STATUS_INSUFFICIENT_RESOURCES";
902   default:
903     return "unknown error";
904   }
905 }
906 PETSC_EXTERN const char *PetscHIPSolverGetErrorName(hipsolverStatus_t status)
907 {
908   switch (status) {
909   case HIPSOLVER_STATUS_SUCCESS:
910     return "HIPSOLVER_STATUS_SUCCESS";
911   case HIPSOLVER_STATUS_NOT_INITIALIZED:
912     return "HIPSOLVER_STATUS_NOT_INITIALIZED";
913   case HIPSOLVER_STATUS_ALLOC_FAILED:
914     return "HIPSOLVER_STATUS_ALLOC_FAILED";
915   case HIPSOLVER_STATUS_MAPPING_ERROR:
916     return "HIPSOLVER_STATUS_MAPPING_ERROR";
917   case HIPSOLVER_STATUS_INVALID_VALUE:
918     return "HIPSOLVER_STATUS_INVALID_VALUE";
919   case HIPSOLVER_STATUS_EXECUTION_FAILED:
920     return "HIPSOLVER_STATUS_EXECUTION_FAILED";
921   case HIPSOLVER_STATUS_INTERNAL_ERROR:
922     return "HIPSOLVER_STATUS_INTERNAL_ERROR";
923   case HIPSOLVER_STATUS_NOT_SUPPORTED:
924     return "HIPSOLVER_STATUS_NOT_SUPPORTED ";
925   case HIPSOLVER_STATUS_ARCH_MISMATCH:
926     return "HIPSOLVER_STATUS_ARCH_MISMATCH";
927   case HIPSOLVER_STATUS_HANDLE_IS_NULLPTR:
928     return "HIPSOLVER_STATUS_HANDLE_IS_NULLPTR";
929   case HIPSOLVER_STATUS_INVALID_ENUM:
930     return "HIPSOLVER_STATUS_INVALID_ENUM";
931   case HIPSOLVER_STATUS_UNKNOWN:
932   default:
933     return "HIPSOLVER_STATUS_UNKNOWN";
934   }
935 }
936 #endif
937 
938 /*@C
939   PetscMPIErrorString - Given an MPI error code returns the `MPI_Error_string()` appropriately
940   formatted for displaying with the PETSc error handlers.
941 
942   Input Parameter:
943 . err - the MPI error code
944 
945   Output Parameter:
946 . string - the MPI error message, should declare its length to be larger than `MPI_MAX_ERROR_STRING`
947 
948   Level: developer
949 
950   Note:
951   Does not return an error code or do error handling because it may be called from inside an error handler
952 
953 .seealso: `PetscErrorCode` `PetscErrorMessage()`
954 @*/
955 void PetscMPIErrorString(PetscMPIInt err, char *string)
956 {
957   char        errorstring[MPI_MAX_ERROR_STRING];
958   PetscMPIInt len, j = 0;
959 
960   MPI_Error_string(err, (char *)errorstring, &len);
961   for (PetscMPIInt i = 0; i < len; i++) {
962     string[j++] = errorstring[i];
963     if (errorstring[i] == '\n') {
964       for (PetscMPIInt k = 0; k < 16; k++) string[j++] = ' ';
965     }
966   }
967   string[j] = 0;
968 }
969