xref: /petsc/src/sys/error/errtrace.c (revision 73fdd05bb67e49f40fd8fd311695ff6fdf0b9b8a)
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 
9 /*@C
10    PetscIgnoreErrorHandler - Deprecated, use `PetscReturnErrorHandler()`. Ignores the error, allows program to continue as if error did not occure
11 
12    Not Collective
13 
14    Input Parameters:
15 +  comm - communicator over which error occurred
16 .  line - the line number of the error (indicated by __LINE__)
17 .  file - the file in which the error was detected (indicated by __FILE__)
18 .  mess - an error text string, usually just printed to the screen
19 .  n - the generic error number
20 .  p - specific error number
21 -  ctx - error handler context
22 
23    Level: developer
24 
25    Note:
26    Users do not directly call this routine
27 
28 .seealso: `PetscReturnErrorHandler()`
29  @*/
30 PetscErrorCode PetscIgnoreErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx)
31 {
32   return n;
33 }
34 
35 /* ---------------------------------------------------------------------------------------*/
36 
37 static char      arch[128], hostname[128], username[128], pname[PETSC_MAX_PATH_LEN], date[128];
38 static PetscBool PetscErrorPrintfInitializeCalled = PETSC_FALSE;
39 static char      version[256];
40 
41 /*
42    Initializes arch, hostname, username, date so that system calls do NOT need
43    to be made during the error handler.
44 */
45 PetscErrorCode PetscErrorPrintfInitialize(void)
46 {
47   PetscBool use_stdout = PETSC_FALSE, use_none = PETSC_FALSE;
48 
49   PetscFunctionBegin;
50   PetscCall(PetscGetArchType(arch, sizeof(arch)));
51   PetscCall(PetscGetHostName(hostname, sizeof(hostname)));
52   PetscCall(PetscGetUserName(username, sizeof(username)));
53   PetscCall(PetscGetProgramName(pname, sizeof(pname)));
54   PetscCall(PetscGetDate(date, sizeof(date)));
55   PetscCall(PetscGetVersion(version, sizeof(version)));
56 
57   PetscCall(PetscOptionsGetBool(NULL, NULL, "-error_output_stdout", &use_stdout, NULL));
58   if (use_stdout) PETSC_STDERR = PETSC_STDOUT;
59   PetscCall(PetscOptionsGetBool(NULL, NULL, "-error_output_none", &use_none, NULL));
60   if (use_none) PetscErrorPrintf = PetscErrorPrintfNone;
61   PetscErrorPrintfInitializeCalled = PETSC_TRUE;
62   PetscFunctionReturn(PETSC_SUCCESS);
63 }
64 
65 PetscErrorCode PetscErrorPrintfNone(const char format[], ...)
66 {
67   return PETSC_SUCCESS;
68 }
69 
70 PetscErrorCode PetscErrorPrintfDefault(const char format[], ...)
71 {
72   va_list          Argp;
73   static PetscBool PetscErrorPrintfCalled = PETSC_FALSE;
74   PetscErrorCode   ierr;
75 
76   /*
77       This function does not call PetscFunctionBegin and PetscFunctionReturn() because
78     it may be called by PetscStackView().
79 
80       This function does not do error checking because it is called by the error handlers.
81   */
82 
83   if (!PetscErrorPrintfCalled) {
84     PetscErrorPrintfCalled = PETSC_TRUE;
85 
86     /*
87         On the SGI machines and Cray T3E, if errors are generated  "simultaneously" by
88       different processors, the messages are printed all jumbled up; to try to
89       prevent this we have each processor wait based on their rank
90     */
91 #if defined(PETSC_CAN_SLEEP_AFTER_ERROR)
92     {
93       PetscMPIInt rank = PetscGlobalRank > 8 ? 8 : PetscGlobalRank;
94       ierr             = PetscSleep((PetscReal)rank);
95       (void)ierr;
96     }
97 #endif
98   }
99 
100   ierr = PetscFPrintf(PETSC_COMM_SELF, PETSC_STDERR, "[%d]PETSC ERROR: ", PetscGlobalRank);
101   va_start(Argp, format);
102   ierr = (*PetscVFPrintf)(PETSC_STDERR, format, Argp);
103   (void)ierr;
104   va_end(Argp);
105   return PETSC_SUCCESS;
106 }
107 
108 /*
109    On some systems when the stderr is nested through several levels of shell script
110    before being passed to a file the isatty() falsely returns true resulting in
111    the screen highlight variables being passed through the test harness. Therefore
112    simply do not highlight when the PETSC_STDERR is PETSC_STDOUT.
113 */
114 static void PetscErrorPrintfHilight(void)
115 {
116 #if defined(PETSC_HAVE_UNISTD_H) && defined(PETSC_USE_ISATTY)
117   if (PetscErrorPrintf == PetscErrorPrintfDefault && PETSC_STDERR != PETSC_STDOUT) {
118     if (isatty(fileno(PETSC_STDERR))) fprintf(PETSC_STDERR, "\033[1;31m");
119   }
120 #endif
121 }
122 
123 static void PetscErrorPrintfNormal(void)
124 {
125 #if defined(PETSC_HAVE_UNISTD_H) && defined(PETSC_USE_ISATTY)
126   if (PetscErrorPrintf == PetscErrorPrintfDefault && PETSC_STDERR != PETSC_STDOUT) {
127     if (isatty(fileno(PETSC_STDERR))) fprintf(PETSC_STDERR, "\033[0;39m\033[0;49m");
128   }
129 #endif
130 }
131 
132 PETSC_EXTERN PetscErrorCode PetscOptionsViewError(void);
133 
134 /*@C
135 
136    PetscTraceBackErrorHandler - Default error handler routine that generates
137    a traceback on error detection.
138 
139    Not Collective
140 
141    Input Parameters:
142 +  comm - communicator over which error occurred
143 .  line - the line number of the error (indicated by __LINE__)
144 .  file - the file in which the error was detected (indicated by __FILE__)
145 .  mess - an error text string, usually just printed to the screen
146 .  n - the generic error number
147 .  p - `PETSC_ERROR_INITIAL` if this is the first call the error handler, otherwise `PETSC_ERROR_REPEAT`
148 -  ctx - error handler context
149 
150   Options Database Keys:
151 +  -error_output_stdout - output the error messages to stdout instead of the default stderr
152 -  -error_output_none - do not output the error messages
153 
154    Notes:
155    Users do not directly call this routine
156 
157    Use `PetscPushErrorHandler()` to set the desired error handler.
158 
159    Level: developer
160 
161 .seealso: `PetscError()`, `PetscPushErrorHandler()`, `PetscPopErrorHandler()`, `PetscAttachDebuggerErrorHandler()`,
162           `PetscAbortErrorHandler()`, `PetscMPIAbortErrorHandler()`, `PetscReturnErrorHandler()`, `PetscEmacsClientErrorHandler()`
163  @*/
164 PetscErrorCode PetscTraceBackErrorHandler(MPI_Comm comm, int line, const char *fun, const char *file, PetscErrorCode n, PetscErrorType p, const char *mess, void *ctx)
165 {
166   PetscErrorCode ierr;
167   PetscLogDouble mem, rss;
168   PetscBool      flg1 = PETSC_FALSE, flg2 = PETSC_FALSE, flg3 = PETSC_FALSE;
169   PetscMPIInt    rank = 0;
170 
171   if (comm != PETSC_COMM_SELF) MPI_Comm_rank(comm, &rank);
172 
173   if (rank == 0 && (!PetscCIEnabledPortableErrorOutput || PetscGlobalRank == 0)) {
174     static int cnt = 1;
175 
176     if (cnt == 1) {
177       PetscErrorPrintfHilight();
178       ierr = (*PetscErrorPrintf)("--------------------- Error Message --------------------------------------------------------------\n");
179       PetscErrorPrintfNormal();
180       if (n == PETSC_ERR_MEM) {
181         ierr = (*PetscErrorPrintf)("Out of memory. This could be due to allocating\n");
182         ierr = (*PetscErrorPrintf)("too large an object or bleeding by not properly\n");
183         ierr = (*PetscErrorPrintf)("destroying unneeded objects.\n");
184         ierr = PetscMallocGetCurrentUsage(&mem);
185         ierr = PetscMemoryGetCurrentUsage(&rss);
186         ierr = PetscOptionsGetBool(NULL, NULL, "-malloc_dump", &flg1, NULL);
187         ierr = PetscOptionsGetBool(NULL, NULL, "-malloc_view", &flg2, NULL);
188         ierr = PetscOptionsHasName(NULL, NULL, "-malloc_view_threshold", &flg3);
189         if (flg2 || flg3) ierr = PetscMallocView(stdout);
190         else {
191           ierr = (*PetscErrorPrintf)("Memory allocated %.0f Memory used by process %.0f\n", mem, rss);
192           if (flg1) ierr = PetscMallocDump(stdout);
193           else ierr = (*PetscErrorPrintf)("Try running with -malloc_dump or -malloc_view for info.\n");
194         }
195       } else {
196         const char *text;
197         ierr = PetscErrorMessage(n, &text, NULL);
198         if (text) ierr = (*PetscErrorPrintf)("%s\n", text);
199       }
200       if (mess) ierr = (*PetscErrorPrintf)("%s\n", mess);
201       ierr = PetscOptionsLeftError();
202       ierr = (*PetscErrorPrintf)("See https://petsc.org/release/faq/ for trouble shooting.\n");
203       if (!PetscCIEnabledPortableErrorOutput) {
204         ierr = (*PetscErrorPrintf)("%s\n", version);
205         if (PetscErrorPrintfInitializeCalled) ierr = (*PetscErrorPrintf)("%s on a %s named %s by %s %s\n", pname, arch, hostname, username, date);
206         ierr = (*PetscErrorPrintf)("Configure options %s\n", petscconfigureoptions);
207       }
208     }
209     /* print line of stack trace */
210     if (fun) ierr = (*PetscErrorPrintf)("#%d %s() at %s:%d\n", cnt++, fun, PetscCIFilename(file), PetscCILinenumber(line));
211     else if (file) ierr = (*PetscErrorPrintf)("#%d %s:%d\n", cnt++, PetscCIFilename(file), PetscCILinenumber(line));
212     if (fun) {
213       PetscBool ismain = PETSC_FALSE;
214 
215       ierr = PetscStrncmp(fun, "main", 4, &ismain);
216       if (ismain) {
217         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);
218         ierr = PetscOptionsViewError();
219         PetscErrorPrintfHilight();
220         ierr = (*PetscErrorPrintf)("----------------End of Error Message -------send entire error message to petsc-maint@mcs.anl.gov----------\n");
221         PetscErrorPrintfNormal();
222       }
223     }
224   } else {
225     /* do not print error messages since process 0 will print them, sleep before aborting so will not accidentally kill process 0*/
226     ierr = PetscSleep(10.0);
227     exit(0);
228   }
229   (void)ierr;
230   return n;
231 }
232