xref: /petsc/src/sys/error/pstack.c (revision 697336901c45ac77e1fd620fe1fca906cf3f95c8)
1 
2 #include <petsc/private/petscimpl.h> /*I  "petscsys.h"   I*/
3 
4 #if defined(PETSC_USE_DEBUG) && !defined(PETSC_HAVE_THREADSAFETY)
5 PetscStack petscstack;
6 #endif
7 
8 #if defined(PETSC_HAVE_SAWS)
9   #include <petscviewersaws.h>
10 
11 static PetscBool amsmemstack = PETSC_FALSE;
12 
13 /*@C
14   PetscStackSAWsGrantAccess - Grants access of the PETSc stack frames to the SAWs publisher
15 
16   Collective on `PETSC_COMM_WORLD`?
17 
18   Level: developer
19 
20   Developer Notes:
21   Cannot use `PetscFunctionBegin`/`PetrscFunctionReturn()` or `PetscCallSAWs()` since it may be
22   used within those routines
23 
24 .seealso: `PetscObjectSetName()`, `PetscObjectSAWsViewOff()`, `PetscObjectSAWsTakeAccess()`
25 @*/
26 void PetscStackSAWsGrantAccess(void)
27 {
28   if (amsmemstack) {
29     /* ignore any errors from SAWs */
30     SAWs_Unlock();
31   }
32 }
33 
34 /*@C
35   PetscStackSAWsTakeAccess - Takes access of the PETSc stack frames from the SAWs publisher
36 
37   Collective on `PETSC_COMM_WORLD`?
38 
39   Level: developer
40 
41   Developer Notes:
42   Cannot use `PetscFunctionBegin`/`PetscFunctionReturn()` or `PetscCallSAWs()` since it may be
43   used within those routines
44 
45 .seealso: `PetscObjectSetName()`, `PetscObjectSAWsViewOff()`, `PetscObjectSAWsGrantAccess()`
46 @*/
47 void PetscStackSAWsTakeAccess(void)
48 {
49   if (amsmemstack) {
50     /* ignore any errors from SAWs */
51     SAWs_Lock();
52   }
53 }
54 
55 PetscErrorCode PetscStackViewSAWs(void)
56 {
57   PetscMPIInt rank;
58 
59   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
60   if (rank) return PETSC_SUCCESS;
61   #if PetscDefined(USE_DEBUG)
62   PetscCallSAWs(SAWs_Register, ("/PETSc/Stack/functions", petscstack.function, 20, SAWs_READ, SAWs_STRING));
63   PetscCallSAWs(SAWs_Register, ("/PETSc/Stack/__current_size", &petscstack.currentsize, 1, SAWs_READ, SAWs_INT));
64   #endif
65   amsmemstack = PETSC_TRUE;
66   return PETSC_SUCCESS;
67 }
68 
69 PetscErrorCode PetscStackSAWsViewOff(void)
70 {
71   PetscFunctionBegin;
72   if (!amsmemstack) PetscFunctionReturn(PETSC_SUCCESS);
73   PetscCallSAWs(SAWs_Delete, ("/PETSc/Stack"));
74   amsmemstack = PETSC_FALSE;
75   PetscFunctionReturn(PETSC_SUCCESS);
76 }
77 #endif /* PETSC_HAVE_SAWS */
78 
79 #if PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)
80 PetscErrorCode PetscStackSetCheck(PetscBool check)
81 {
82   petscstack.check = check;
83   return PETSC_SUCCESS;
84 }
85 
86 PetscErrorCode PetscStackReset(void)
87 {
88   memset(&petscstack, 0, sizeof(petscstack));
89   return PETSC_SUCCESS;
90 }
91 
92 /*
93   PetscStackView - Print the current (default) PETSc stack to an ASCII file
94 
95   Not Collective
96 
97   Input Parameter:
98 . file - the file pointer, or `NULL` to use `PETSC_STDOUT`
99 
100   Level: developer
101 
102   Notes:
103   In debug mode PETSc maintains a stack of the current function calls that can be used to help
104   to quickly see where a problem has occurred, for example, when a signal is received. It is
105   recommended to use the debugger if extensive information is needed to help debug the problem.
106 
107   The default stack is a global variable called `petscstack`.
108 
109 .seealso: `PetscAttachDebugger()`, `PetscStackCopy()`, `PetscStackPrint()`, `PetscStackSAWsGrantAccess()`, `PetscStackSAWsTakeAccess()`
110 */
111 PetscErrorCode PetscStackView(FILE *file)
112 {
113   if (!file) file = PETSC_STDOUT;
114   if (petscstack.currentsize < 0) {
115     /* < 0 is absolutely a corrupted stack, but this function is usually called in an error
116      * handler, which are not capable of recovering from errors so best we can do is print
117      * this warning */
118     fprintf(file, "PetscStack is definitely corrupted with stack size %d\n", petscstack.currentsize);
119   } else if (petscstack.currentsize == 0) {
120     if (file == PETSC_STDOUT) {
121       PetscCall((*PetscErrorPrintf)("No error traceback is available, the problem could be in the main program. \n"));
122     } else {
123       fprintf(file, "No error traceback is available, the problem could be in the main program. \n");
124     }
125   } else {
126     char *ptr = NULL;
127 
128     if (file == PETSC_STDOUT) {
129       PetscCall((*PetscErrorPrintf)("The line numbers in the error traceback are not always exact.\n"));
130       for (int i = petscstack.currentsize - 1, j = 1; i >= 0; --i, ++j) {
131         if (petscstack.file[i]) PetscCall((*PetscErrorPrintf)("#%d %s() at %s:%d\n", j, petscstack.function[i], PetscCIFilename(petscstack.file[i]), PetscCILinenumber(petscstack.line[i])));
132         else {
133           PetscCall(PetscStrstr(petscstack.function[i], " ", &ptr));
134           if (!ptr) PetscCall((*PetscErrorPrintf)("#%d %s()\n", j, petscstack.function[i]));
135           else PetscCall((*PetscErrorPrintf)("#%d %s\n", j, petscstack.function[i]));
136         }
137       }
138     } else {
139       fprintf(file, "The line numbers in the error traceback are not always exact.\n");
140       for (int i = petscstack.currentsize - 1, j = 1; i >= 0; --i, ++j) {
141         if (petscstack.file[i]) fprintf(file, "[%d] #%d %s() at %s:%d\n", PetscGlobalRank, j, petscstack.function[i], PetscCIFilename(petscstack.file[i]), PetscCILinenumber(petscstack.line[i]));
142         else {
143           PetscCall(PetscStrstr(petscstack.function[i], " ", &ptr));
144           if (!ptr) fprintf(file, "[%d] #%d %s()\n", PetscGlobalRank, j, petscstack.function[i]);
145           else fprintf(file, "[%d] #%d %s\n", PetscGlobalRank, j, petscstack.function[i]);
146         }
147       }
148     }
149   }
150   return PETSC_SUCCESS;
151 }
152 
153 /*
154   PetscStackCopy - Copy the information from one PETSc stack to another
155 
156   Not Collective
157 
158   Input Parameter:
159 . sint - the stack to be copied from
160 
161   Output Parameter:
162 . sout - the stack to be copied to, this stack must already exist
163 
164   Level: developer
165 
166   Note:
167   In debug mode PETSc maintains a stack of the current function calls that can be used to help
168   to quickly see where a problem has occurred, for example, when a signal is received. It is
169   recommended to use the debugger if extensive information is needed to help debug the problem.
170 
171 .seealso: `PetscAttachDebugger()`, `PetscStackView()`
172 */
173 PetscErrorCode PetscStackCopy(PetscStack *sint, PetscStack *sout)
174 {
175   if (sint) {
176     for (int i = 0; i < sint->currentsize; ++i) {
177       sout->function[i]     = sint->function[i];
178       sout->file[i]         = sint->file[i];
179       sout->line[i]         = sint->line[i];
180       sout->petscroutine[i] = sint->petscroutine[i];
181     }
182     sout->currentsize = sint->currentsize;
183   } else {
184     sout->currentsize = 0;
185   }
186   return PETSC_SUCCESS;
187 }
188 
189 /*
190   PetscStackPrint - Prints a given PETSc stack to an ASCII file
191 
192   Not Collective
193 
194   Input Parameters:
195 + sint - the PETSc stack to print
196 - file - the file pointer
197 
198   Level: developer
199 
200   Notes:
201   In debug mode PETSc maintains a stack of the current function calls that can be used to help
202   to quickly see where a problem has occurred, for example, when a signal is received. It is
203   recommended to use the debugger if extensive information is needed to help debug the problem.
204 
205   The default stack is a global variable called `petscstack`.
206 
207   Developer Note:
208   `PetscStackPrint()` and `PetscStackView()` should be merged into a single API.
209 
210 .seealso: `PetscAttachDebugger()`, `PetscStackCopy()`, `PetscStackView()`
211 */
212 PetscErrorCode PetscStackPrint(PetscStack *sint, FILE *fp)
213 {
214   if (sint) {
215     for (int i = sint->currentsize - 2; i >= 0; --i) {
216       if (sint->file[i]) fprintf(fp, "      [%d]  %s() at %s:%d\n", PetscGlobalRank, sint->function[i], PetscCIFilename(sint->file[i]), PetscCILinenumber(sint->line[i]));
217       else fprintf(fp, "      [%d]  %s()\n", PetscGlobalRank, sint->function[i]);
218     }
219   }
220   return PETSC_SUCCESS;
221 }
222 #endif /* PetscDefined(USE_DEBUG) */
223