xref: /petsc/src/sys/error/errtrace.c (revision 31d78bcd2b98084dc1368b20eb1129c8b9fb39fe)
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     PetscBool  ismain;
175     static int cnt = 1;
176 
177     if (cnt == 1) {
178       PetscErrorPrintfHilight();
179       ierr = (*PetscErrorPrintf)("--------------------- Error Message --------------------------------------------------------------\n");
180       PetscErrorPrintfNormal();
181       if (n == PETSC_ERR_MEM) {
182         ierr = (*PetscErrorPrintf)("Out of memory. This could be due to allocating\n");
183         ierr = (*PetscErrorPrintf)("too large an object or bleeding by not properly\n");
184         ierr = (*PetscErrorPrintf)("destroying unneeded objects.\n");
185         ierr = PetscMallocGetCurrentUsage(&mem);
186         ierr = PetscMemoryGetCurrentUsage(&rss);
187         ierr = PetscOptionsGetBool(NULL, NULL, "-malloc_dump", &flg1, NULL);
188         ierr = PetscOptionsGetBool(NULL, NULL, "-malloc_view", &flg2, NULL);
189         ierr = PetscOptionsHasName(NULL, NULL, "-malloc_view_threshold", &flg3);
190         if (flg2 || flg3) ierr = PetscMallocView(stdout);
191         else {
192           ierr = (*PetscErrorPrintf)("Memory allocated %.0f Memory used by process %.0f\n", mem, rss);
193           if (flg1) ierr = PetscMallocDump(stdout);
194           else ierr = (*PetscErrorPrintf)("Try running with -malloc_dump or -malloc_view for info.\n");
195         }
196       } else {
197         const char *text;
198         ierr = PetscErrorMessage(n, &text, NULL);
199         if (text) ierr = (*PetscErrorPrintf)("%s\n", text);
200       }
201       if (mess) ierr = (*PetscErrorPrintf)("%s\n", mess);
202       ierr = PetscOptionsLeftError();
203       ierr = (*PetscErrorPrintf)("See https://petsc.org/release/faq/ for trouble shooting.\n");
204       if (!PetscCIEnabledPortableErrorOutput) {
205         ierr = (*PetscErrorPrintf)("%s\n", version);
206         if (PetscErrorPrintfInitializeCalled) ierr = (*PetscErrorPrintf)("%s on a %s named %s by %s %s\n", pname, arch, hostname, username, date);
207         ierr = (*PetscErrorPrintf)("Configure options %s\n", petscconfigureoptions);
208       }
209     }
210     /* print line of stack trace */
211     if (fun) ierr = (*PetscErrorPrintf)("#%d %s() at %s:%d\n", cnt++, fun, PetscCIFilename(file), PetscCILinenumber(line));
212     else if (file) ierr = (*PetscErrorPrintf)("#%d %s:%d\n", cnt++, PetscCIFilename(file), PetscCILinenumber(line));
213     if (fun) {
214       ierr = PetscStrncmp(fun, "main", 4, &ismain);
215       if (ismain) {
216         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);
217         ierr = PetscOptionsViewError();
218         PetscErrorPrintfHilight();
219         ierr = (*PetscErrorPrintf)("----------------End of Error Message -------send entire error message to petsc-maint@mcs.anl.gov----------\n");
220         PetscErrorPrintfNormal();
221       }
222     }
223   } else {
224     /* do not print error messages since process 0 will print them, sleep before aborting so will not accidentally kill process 0*/
225     ierr = PetscSleep(10.0);
226     exit(0);
227   }
228   (void)ierr;
229   return n;
230 }
231