xref: /petsc/src/sys/error/errtrace.c (revision 4ad8454beace47809662cdae21ee081016eaa39a)
1 #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for fileno() */
2 #include <petscsys.h>                    /*I "petscsys.h" I*/
3 #include <petsc/private/petscimpl.h>
4 #include <petscconfiginfo.h>
5 #if defined(PETSC_HAVE_UNISTD_H)
6   #include <unistd.h>
7 #endif
8 #include "err.h"
9 #include <petsc/private/logimpl.h> // PETSC_TLS
10 
11 /*@C
12   PetscIgnoreErrorHandler - Deprecated, use `PetscReturnErrorHandler()`. Ignores the error, allows program to continue as if error did not occur
13 
14   Not Collective
15 
16   Input Parameters:
17 + comm - communicator over which error occurred
18 . line - the line number of the error (indicated by __LINE__)
19 . fun  - the function name
20 . file - the file in which the error was detected (indicated by __FILE__)
21 . mess - an error text string, usually just printed to the screen
22 . n    - the generic error number
23 . p    - specific error number
24 - ctx  - error handler context
25 
26   Level: developer
27 
28   Note:
29   Users do not directly call this routine
30 
31 .seealso: `PetscReturnErrorHandler()`
32  @*/
33 PetscErrorCode PetscIgnoreErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx)
34 {
35   (void)comm;
36   (void)line;
37   (void)fun;
38   (void)file;
39   (void)p;
40   (void)mess;
41   (void)ctx;
42   return n;
43 }
44 
45 /* ---------------------------------------------------------------------------------------*/
46 
47 static char      arch[128], hostname[128], username[128], pname[PETSC_MAX_PATH_LEN], date[128];
48 static PetscBool PetscErrorPrintfInitializeCalled = PETSC_FALSE;
49 static char      version[256];
50 
51 /*
52    Initializes arch, hostname, username, date so that system calls do NOT need
53    to be made during the error handler.
54 */
55 PetscErrorCode PetscErrorPrintfInitialize(void)
56 {
57   PetscBool use_stdout = PETSC_FALSE, use_none = PETSC_FALSE;
58 
59   PetscFunctionBegin;
60   PetscCall(PetscGetArchType(arch, sizeof(arch)));
61   PetscCall(PetscGetHostName(hostname, sizeof(hostname)));
62   PetscCall(PetscGetUserName(username, sizeof(username)));
63   PetscCall(PetscGetProgramName(pname, sizeof(pname)));
64   PetscCall(PetscGetDate(date, sizeof(date)));
65   PetscCall(PetscGetVersion(version, sizeof(version)));
66 
67   PetscCall(PetscOptionsGetBool(NULL, NULL, "-error_output_stdout", &use_stdout, NULL));
68   if (use_stdout) PETSC_STDERR = PETSC_STDOUT;
69   PetscCall(PetscOptionsGetBool(NULL, NULL, "-error_output_none", &use_none, NULL));
70   if (use_none) PetscErrorPrintf = PetscErrorPrintfNone;
71   PetscErrorPrintfInitializeCalled = PETSC_TRUE;
72   PetscFunctionReturn(PETSC_SUCCESS);
73 }
74 
75 PetscErrorCode PetscErrorPrintfNone(const char format[], ...)
76 {
77   return PETSC_SUCCESS;
78 }
79 
80 PetscErrorCode PetscErrorPrintfDefault(const char format[], ...)
81 {
82   va_list          Argp;
83   static PetscBool PetscErrorPrintfCalled = PETSC_FALSE;
84   PetscErrorCode   ierr;
85 
86   /*
87       This function does not call PetscFunctionBegin and PetscFunctionReturn() because
88     it may be called by PetscStackView().
89 
90       This function does not do error checking because it is called by the error handlers.
91   */
92 
93   if (!PetscErrorPrintfCalled) {
94     PetscErrorPrintfCalled = PETSC_TRUE;
95 
96     /*
97         On the SGI machines and Cray T3E, if errors are generated  "simultaneously" by
98       different processors, the messages are printed all jumbled up; to try to
99       prevent this we have each processor wait based on their rank
100     */
101 #if defined(PETSC_CAN_SLEEP_AFTER_ERROR)
102     {
103       PetscMPIInt rank = PetscGlobalRank > 8 ? 8 : PetscGlobalRank;
104       ierr             = PetscSleep((PetscReal)rank);
105       (void)ierr;
106     }
107 #endif
108   }
109 
110   ierr = PetscFPrintf(PETSC_COMM_SELF, PETSC_STDERR, "[%d]PETSC ERROR: ", PetscGlobalRank);
111   va_start(Argp, format);
112   ierr = (*PetscVFPrintf)(PETSC_STDERR, format, Argp);
113   (void)ierr;
114   va_end(Argp);
115   return PETSC_SUCCESS;
116 }
117 
118 /*
119    On some systems when the stderr is nested through several levels of shell script
120    before being passed to a file the isatty() falsely returns true resulting in
121    the screen highlight variables being passed through the test harness. Therefore
122    simply do not highlight when the PETSC_STDERR is PETSC_STDOUT.
123 */
124 static void PetscErrorPrintfHilight(void)
125 {
126 #if defined(PETSC_HAVE_UNISTD_H) && defined(PETSC_USE_ISATTY)
127   if (PetscErrorPrintf == PetscErrorPrintfDefault && PETSC_STDERR != PETSC_STDOUT) {
128     if (isatty(fileno(PETSC_STDERR))) fprintf(PETSC_STDERR, "\033[1;31m");
129   }
130 #endif
131 }
132 
133 static void PetscErrorPrintfNormal(void)
134 {
135 #if defined(PETSC_HAVE_UNISTD_H) && defined(PETSC_USE_ISATTY)
136   if (PetscErrorPrintf == PetscErrorPrintfDefault && PETSC_STDERR != PETSC_STDOUT) {
137     if (isatty(fileno(PETSC_STDERR))) fprintf(PETSC_STDERR, "\033[0;39m\033[0;49m");
138   }
139 #endif
140 }
141 
142 PETSC_EXTERN PetscErrorCode PetscOptionsViewError(void);
143 
144 static PETSC_TLS PetscBool petsc_traceback_error_silent = PETSC_FALSE;
145 
146 /*@C
147 
148   PetscTraceBackErrorHandler - Default error handler routine that generates
149   a traceback on error detection.
150 
151   Not Collective
152 
153   Input Parameters:
154 + comm - communicator over which error occurred
155 . line - the line number of the error (usually indicated by `__LINE__` in the calling routine)
156 . fun  - the function name
157 . file - the file in which the error was detected (usually indicated by `__FILE__` in the calling routine)
158 . mess - an error text string, usually just printed to the screen
159 . n    - the generic error number
160 . p    - `PETSC_ERROR_INITIAL` if this is the first call the error handler, otherwise `PETSC_ERROR_REPEAT`
161 - ctx  - error handler context
162 
163   Options Database Keys:
164 + -error_output_stdout - output the error messages to `stdout` instead of the default `stderr`
165 - -error_output_none   - do not output the error messages
166 
167   Notes:
168   Users do not directly call this routine
169 
170   Use `PetscPushErrorHandler()` to set the desired error handler.
171 
172   Level: developer
173 
174 .seealso: `PetscError()`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscAttachDebuggerErrorHandler()`,
175           `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscReturnErrorHandler()`, `PetscEmacsClientErrorHandler()`,
176            `PETSC_ERROR_INITIAL`, `PETSC_ERROR_REPEAT`, `PetscErrorCode`, `PetscErrorType`
177  @*/
178 PetscErrorCode PetscTraceBackErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx)
179 {
180   PetscErrorCode ierr;
181   PetscMPIInt    rank = 0;
182 
183   (void)ctx;
184   if (comm != PETSC_COMM_SELF) MPI_Comm_rank(comm, &rank);
185 
186   // reinitialize the error handler when a new initializing error is detected
187   if (p != PETSC_ERROR_REPEAT) {
188     petsc_traceback_error_silent = PETSC_FALSE;
189     if (PetscCIEnabledPortableErrorOutput) {
190       PetscMPIInt size = 1;
191 
192       if (comm != MPI_COMM_NULL) MPI_Comm_size(comm, &size);
193       petscabortmpifinalize = (size == PetscGlobalSize) ? PETSC_TRUE : PETSC_FALSE;
194     }
195   }
196 
197   if (rank == 0 && (!PetscCIEnabledPortableErrorOutput || PetscGlobalRank == 0) && (p != PETSC_ERROR_REPEAT || !petsc_traceback_error_silent)) {
198     static int cnt = 1;
199 
200     if (p == PETSC_ERROR_INITIAL) {
201       PetscErrorPrintfHilight();
202       ierr = (*PetscErrorPrintf)("--------------------- Error Message --------------------------------------------------------------\n");
203       PetscErrorPrintfNormal();
204       if (cnt > 1) {
205         ierr = (*PetscErrorPrintf)("  It appears a new error in the code was triggered after a previous error, possibly because:\n");
206         ierr = (*PetscErrorPrintf)("  -  The first error was not properly handled via (for example) the use of\n");
207         ierr = (*PetscErrorPrintf)("     PetscCall(TheFunctionThatErrors()); or\n");
208         ierr = (*PetscErrorPrintf)("  -  The second error was triggered while handling the first error.\n");
209         ierr = (*PetscErrorPrintf)("  Above is the traceback for the previous unhandled error, below the traceback for the next error\n");
210         ierr = (*PetscErrorPrintf)("  ALL ERRORS in the PETSc libraries are fatal, you should add the appropriate error checking to the code\n");
211         cnt  = 1;
212       }
213     }
214     if (cnt == 1) {
215       if (n == PETSC_ERR_MEM || n == PETSC_ERR_MEM_LEAK) ierr = PetscErrorMemoryMessage(n);
216       else {
217         const char *text;
218         ierr = PetscErrorMessage(n, &text, NULL);
219         if (text) ierr = (*PetscErrorPrintf)("%s\n", text);
220       }
221       if (mess) ierr = (*PetscErrorPrintf)("%s\n", mess);
222       ierr = PetscOptionsLeftError();
223       ierr = (*PetscErrorPrintf)("See https://petsc.org/release/faq/ for trouble shooting.\n");
224       if (!PetscCIEnabledPortableErrorOutput) {
225         ierr = (*PetscErrorPrintf)("%s\n", version);
226         if (PetscErrorPrintfInitializeCalled) ierr = (*PetscErrorPrintf)("%s on a %s named %s by %s %s\n", pname, arch, hostname, username, date);
227         ierr = (*PetscErrorPrintf)("Configure options %s\n", petscconfigureoptions);
228       }
229     }
230     /* print line of stack trace */
231     if (fun) ierr = (*PetscErrorPrintf)("#%d %s() at %s:%d\n", cnt++, fun, PetscCIFilename(file), PetscCILinenumber(line));
232     else if (file) ierr = (*PetscErrorPrintf)("#%d %s:%d\n", cnt++, PetscCIFilename(file), PetscCILinenumber(line));
233     if (fun) {
234       PetscBool ismain = PETSC_FALSE;
235 
236       ierr = PetscStrncmp(fun, "main", 4, &ismain);
237       if (ismain) {
238         if ((n <= PETSC_ERR_MIN_VALUE) || (n >= PETSC_ERR_MAX_VALUE)) ierr = (*PetscErrorPrintf)("Reached the main program with an out-of-range error code %d. This should never happen\n", n);
239         ierr = PetscOptionsViewError();
240         PetscErrorPrintfHilight();
241         ierr = (*PetscErrorPrintf)("----------------End of Error Message -------send entire error message to petsc-maint@mcs.anl.gov----------\n");
242         PetscErrorPrintfNormal();
243       }
244     }
245   } else {
246     // silence this process's stacktrace if it is not the root of an originating error
247     if (p != PETSC_ERROR_REPEAT && rank) petsc_traceback_error_silent = PETSC_TRUE;
248     if (fun) {
249       PetscBool ismain = PETSC_FALSE;
250 
251       ierr = PetscStrncmp(fun, "main", 4, &ismain);
252       if (ismain && petsc_traceback_error_silent) {
253         /* This results from PetscError() being called in main: PETSCABORT()
254            will be called after the error handler.  But this thread is not the
255            root rank of the communicator that initialized the error.  So sleep
256            to allow the root thread to finish its printing.
257 
258            (Unless this is running CI, in which case do not sleep because
259            we expect all processes to call MPI_Finalize() and make a clean
260            exit.) */
261         if (!PetscCIEnabledPortableErrorOutput) ierr = PetscSleep(10.0);
262       }
263     }
264   }
265   (void)ierr;
266   return n;
267 }
268