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