Actual source code: pstack.c

  1: #include <petsc/private/petscimpl.h>

  3: #if defined(PETSC_USE_DEBUG) && !defined(PETSC_HAVE_THREADSAFETY)
  4: PetscStack petscstack;
  5: #endif

  7: #if defined(PETSC_HAVE_SAWS)
  8: #include <petscviewersaws.h>

 10: static PetscBool amsmemstack = PETSC_FALSE;

 12: /*@
 13:   PetscStackSAWsGrantAccess - Grants access of the PETSc stack frames to the SAWs publisher

 15:   Collective on `PETSC_COMM_WORLD`?

 17:   Level: developer

 19:   Developer Notes:
 20:   Cannot use `PetscFunctionBegin`/`PetscFunctionReturn()` or `PetscCallSAWs()` since it may be
 21:   used within those routines

 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: }

 33: /*@
 34:   PetscStackSAWsTakeAccess - Takes access of the PETSc stack frames from the SAWs publisher

 36:   Collective on `PETSC_COMM_WORLD`?

 38:   Level: developer

 40:   Developer Notes:
 41:   Cannot use `PetscFunctionBegin`/`PetscFunctionReturn()` or `PetscCallSAWs()` since it may be
 42:   used within those routines

 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: }

 54: /*@C
 55:   PetscStackViewSAWs - Publish PETSc's current debug call stack through the SAWs (Scientific Application Web server) so it can be inspected from a remote browser

 57:   Logically Collective on `PETSC_COMM_WORLD`; No Fortran Support

 59:   Level: developer

 61:   Note:
 62:   Only MPI rank 0 publishes; other MPI processes immediately return success. In non-debug builds the stack contents are not published but the call still succeeds.

 64: .seealso: `PetscStackView()`, `PetscStackSAWsViewOff()`, `PetscObjectSAWsViewOff()`
 65: @*/
 66: PetscErrorCode PetscStackViewSAWs(void)
 67: {
 68:   PetscMPIInt rank;

 70:   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
 71:   if (rank) return PETSC_SUCCESS;
 72:   #if PetscDefined(USE_DEBUG)
 73:   PetscCallSAWs(SAWs_Register, ("/PETSc/Stack/functions", petscstack.function, 20, SAWs_READ, SAWs_STRING));
 74:   PetscCallSAWs(SAWs_Register, ("/PETSc/Stack/__current_size", &petscstack.currentsize, 1, SAWs_READ, SAWs_INT));
 75:   #endif
 76:   amsmemstack = PETSC_TRUE;
 77:   return PETSC_SUCCESS;
 78: }

 80: /*@C
 81:   PetscStackSAWsViewOff - Stop publishing the PETSc debug call stack through SAWs (Scientific Application Web server)

 83:   Logically Collective

 85:   Level: developer

 87:   Note:
 88:   No-op when `PetscStackViewSAWs()` was never called. Compiled to a no-op when PETSc is not configured `--with-saws`.

 90: .seealso: `PetscStackViewSAWs()`, `PetscStackView()`, `PetscObjectSAWsViewOff()`
 91: @*/
 92: PetscErrorCode PetscStackSAWsViewOff(void)
 93: {
 94:   PetscFunctionBegin;
 95:   if (!amsmemstack) PetscFunctionReturn(PETSC_SUCCESS);
 96:   PetscCallSAWs(SAWs_Delete, ("/PETSc/Stack"));
 97:   amsmemstack = PETSC_FALSE;
 98:   PetscFunctionReturn(PETSC_SUCCESS);
 99: }
100: #endif /* PETSC_HAVE_SAWS */

102: #if PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)
103: PetscErrorCode PetscStackSetCheck(PetscBool check)
104: {
105:   petscstack.check = check;
106:   return PETSC_SUCCESS;
107: }

109: PetscErrorCode PetscStackReset(void)
110: {
111:   memset(&petscstack, 0, sizeof(petscstack));
112:   return PETSC_SUCCESS;
113: }

115: // PetscClangLinter pragma disable: -fdoc-sowing-chars
116: /*@
117:   PetscStackView - Print the current (default) PETSc stack to an ASCII file

119:   Not Collective, No Fortran Support

121:   Input Parameter:
122: . file - the file pointer, or `NULL` to use `PETSC_STDERR`

124:   Level: developer

126:   Notes:
127:   In debug mode PETSc maintains a stack of the current function calls that can be used to help
128:   to quickly see where a problem has occurred, for example, when a signal is received. It is
129:   recommended to use the debugger if extensive information is needed to help debug the problem.

131:   If `file` is `PETSC_STDERR` (or `NULL`) then `PetscErrorPrintf()` is used to print the stack, otherwise `fprintf()` is used.

133:   The stack is maintained only when PETSc is configured `--with-debugging` and without thread safety; in other configurations this becomes a no-op that returns `PETSC_SUCCESS`.

135:   Developer Note:
136:   The default stack is a global variable called `petscstack`.

138: .seealso: `PetscAttachDebugger()`, `PetscStackCopy()`, `PetscStackPrint()`, `PetscStackSAWsGrantAccess()`, `PetscStackSAWsTakeAccess()`
139: @*/
140: PetscErrorCode PetscStackView(FILE *file)
141: {
142:   if (!file) file = PETSC_STDERR;
143:   if (petscstack.currentsize < 0) {
144:     /* < 0 is absolutely a corrupted stack, but this function is usually called in an error
145:      * handler, which are not capable of recovering from errors so best we can do is print
146:      * this warning */
147:     fprintf(file, "PetscStack is definitely corrupted with stack size %d\n", petscstack.currentsize);
148:   } else if (petscstack.currentsize == 0) {
149:     if (file == PETSC_STDERR) {
150:       PetscCall((*PetscErrorPrintf)("No error traceback is available, the problem could be in the main program. \n"));
151:     } else {
152:       fprintf(file, "No error traceback is available, the problem could be in the main program. \n");
153:     }
154:   } else {
155:     char *ptr = NULL;

157:     if (file == PETSC_STDERR) {
158:       PetscCall((*PetscErrorPrintf)("The line numbers in the error traceback may not be exact.\n"));
159:       for (int i = petscstack.currentsize - 1, j = 1; i >= 0; --i, ++j) {
160:         if (petscstack.file[i]) PetscCall((*PetscErrorPrintf)("#%d %s() at %s:%d\n", j, petscstack.function[i], PetscCIFilename(petscstack.file[i]), PetscCILinenumber(petscstack.line[i])));
161:         else {
162:           PetscCall(PetscStrstr(petscstack.function[i], " ", &ptr));
163:           if (!ptr) PetscCall((*PetscErrorPrintf)("#%d %s()\n", j, petscstack.function[i]));
164:           else PetscCall((*PetscErrorPrintf)("#%d %s\n", j, petscstack.function[i]));
165:         }
166:       }
167:     } else {
168:       fprintf(file, "The line numbers in the error traceback are not always exact.\n");
169:       for (int i = petscstack.currentsize - 1, j = 1; i >= 0; --i, ++j) {
170:         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]));
171:         else {
172:           PetscCall(PetscStrstr(petscstack.function[i], " ", &ptr));
173:           if (!ptr) fprintf(file, "[%d] #%d %s()\n", PetscGlobalRank, j, petscstack.function[i]);
174:           else fprintf(file, "[%d] #%d %s\n", PetscGlobalRank, j, petscstack.function[i]);
175:         }
176:       }
177:     }
178:   }
179:   return PETSC_SUCCESS;
180: }

182: /*@
183:   PetscStackCopy - Copy the information from one PETSc stack to another

185:   Not Collective

187:   Input Parameter:
188: . sint - the stack to be copied from

190:   Output Parameter:
191: . sout - the stack to be copied to, this stack must already exist

193:   Level: developer

195:   Note:
196:   In debug mode PETSc maintains a stack of the current function calls that can be used to help
197:   to quickly see where a problem has occurred, for example, when a signal is received. It is
198:   recommended to use the debugger if extensive information is needed to help debug the problem.

200: .seealso: `PetscAttachDebugger()`, `PetscStackView()`
201: @*/
202: PetscErrorCode PetscStackCopy(PetscStack *sint, PetscStack *sout)
203: {
204:   if (sint) {
205:     for (int i = 0; i < sint->currentsize; ++i) {
206:       sout->function[i]     = sint->function[i];
207:       sout->file[i]         = sint->file[i];
208:       sout->line[i]         = sint->line[i];
209:       sout->petscroutine[i] = sint->petscroutine[i];
210:     }
211:     sout->currentsize = sint->currentsize;
212:   } else {
213:     sout->currentsize = 0;
214:   }
215:   return PETSC_SUCCESS;
216: }

218: // PetscClangLinter pragma disable: -fdoc-sowing-chars
219: /*@
220:   PetscStackPrint - Prints a given PETSc stack to an ASCII file

222:   Not Collective

224:   Input Parameters:
225: + sint - the PETSc stack to print
226: - fp   - the file pointer

228:   Level: developer

230:   Notes:
231:   In debug mode PETSc maintains a stack of the current function calls that can be used to help
232:   to quickly see where a problem has occurred, for example, when a signal is received. It is
233:   recommended to use the debugger if extensive information is needed to help debug the problem.

235:   The default stack is a global variable called `petscstack`.

237:   Developer Note:
238:   `PetscStackPrint()` and `PetscStackView()` should be merged into a single API.

240: .seealso: `PetscAttachDebugger()`, `PetscStackCopy()`, `PetscStackView()`
241: @*/
242: PetscErrorCode PetscStackPrint(PetscStack *sint, FILE *fp)
243: {
244:   if (sint) {
245:     for (int i = sint->currentsize; i >= 0; --i) {
246:       if (sint->file[i]) fprintf(fp, "      [%d]  %s() at %s:%d\n", PetscGlobalRank, sint->function[i], PetscCIFilename(sint->file[i]), PetscCILinenumber(sint->line[i]));
247:       else fprintf(fp, "      [%d]  %s()\n", PetscGlobalRank, sint->function[i]);
248:     }
249:   }
250:   return PETSC_SUCCESS;
251: }
252: #endif /* PetscDefined(USE_DEBUG) */