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