xref: /petsc/src/sys/error/pstack.c (revision 792fecdfe9134cce4d631112660ddd34f063bc17)
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: Cannot use PetscFunctionBegin/Return() or PetscCallSAWs() since it may be used within those routines
21 
22 .seealso: `PetscObjectSetName()`, `PetscObjectSAWsViewOff()`, `PetscObjectSAWsTakeAccess()`
23 
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: Cannot use PetscFunctionBegin/Return() or PetscCallSAWs() since it may be used within those routines
41 
42 .seealso: `PetscObjectSetName()`, `PetscObjectSAWsViewOff()`, `PetscObjectSAWsTakeAccess()`
43 
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 0;
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 0;
65 }
66 
67 PetscErrorCode PetscStackSAWsViewOff(void)
68 {
69   PetscFunctionBegin;
70   if (!amsmemstack) PetscFunctionReturn(0);
71   PetscCallSAWs(SAWs_Delete,("/PETSc/Stack"));
72   amsmemstack = PETSC_FALSE;
73   PetscFunctionReturn(0);
74 }
75 #endif /* PETSC_HAVE_SAWS */
76 
77 #if PetscDefined(USE_DEBUG)
78 PetscErrorCode PetscStackSetCheck(PetscBool check)
79 {
80   petscstack.check = check;
81   return 0;
82 }
83 
84 PetscErrorCode PetscStackReset(void)
85 {
86   memset(&petscstack,0,sizeof(petscstack));
87   return 0;
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       (*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;
125 
126     if (file == PETSC_STDOUT) {
127       (*PetscErrorPrintf)("The EXACT line numbers in the error traceback are not available.\n");
128       (*PetscErrorPrintf)("instead the line number of the start of the function is given.\n");
129       for (int i = petscstack.currentsize-1, j = 1; i >= 0; --i, ++j) {
130         if (petscstack.file[i]) (*PetscErrorPrintf)("#%d %s() at %s:%d\n",j,petscstack.function[i],petscstack.file[i],petscstack.line[i]);
131         else {
132           PetscStrstr(petscstack.function[i]," ",&ptr);
133           if (!ptr) (*PetscErrorPrintf)("#%d %s()\n",j,petscstack.function[i]);
134           else (*PetscErrorPrintf)("#%d %s\n",j,petscstack.function[i]);
135         }
136       }
137     } else {
138       fprintf(file,"The EXACT line numbers in the error traceback are not available.\n");
139       fprintf(file,"Instead the line number of the start of the function is given.\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],petscstack.file[i],petscstack.line[i]);
142         else {
143           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 0;
151 }
152 
153 /*@C
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    Notes:
167    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
168    occurred, for example, when a signal is received. It is recommended to use the debugger if extensive information is needed to
169    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 0;
187 }
188 
189 /*@C
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 to quickly see where a problem has
202    occurred, for example, when a signal is received. It is recommended to use the debugger if extensive information is needed to
203    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],sint->file[i],sint->line[i]);
217       else fprintf(fp,"      [%d]  %s()\n",PetscGlobalRank,sint->function[i]);
218     }
219   }
220   return 0;
221 }
222 #endif /* PetscDefined(USE_DEBUG) */
223