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